# Velt

## Docs

- [null](https://docs.velt.dev/api-reference/api-methods/comments)
- [null](https://docs.velt.dev/api-reference/api-methods/cursors)
- [null](https://docs.velt.dev/api-reference/api-methods/live-state-sync)
- [null](https://docs.velt.dev/api-reference/api-methods/notifications)
- [null](https://docs.velt.dev/api-reference/api-methods/presence)
- [null](https://docs.velt.dev/api-reference/api-methods/recorder)
- [null](https://docs.velt.dev/api-reference/api-methods/rewriter)
- [null](https://docs.velt.dev/api-reference/api-methods/selection)
- [null](https://docs.velt.dev/api-reference/api-methods/velt-client)
- [React Hooks](https://docs.velt.dev/api-reference/hooks/hooks)
- [null](https://docs.velt.dev/api-reference/models/AutocompleteItem)
- [null](https://docs.velt.dev/api-reference/models/Comment)
- [CommentAnnotation](https://docs.velt.dev/api-reference/models/CommentAnnotation)
- [CommentSelectionChangeData](https://docs.velt.dev/api-reference/models/CommentSelectionChangeData)
- [CommentSidebarConfig](https://docs.velt.dev/api-reference/models/CommentSidebarConfig)
- [CommentSidebarCustomActionEventData](https://docs.velt.dev/api-reference/models/CommentSidebarCustomActionEventData)
- [CommentSidebarData](https://docs.velt.dev/api-reference/models/CommentSidebarData)
- [Velt Client Config](https://docs.velt.dev/api-reference/models/Config)
- [ContactListScopeForOrganizationUsers](https://docs.velt.dev/api-reference/models/ContactListScopeForOrganizationUsers)
- [CursorUser](https://docs.velt.dev/api-reference/models/CursorUser)
- [CustomCss](https://docs.velt.dev/api-reference/models/CustomCss)
- [CustomFilter](https://docs.velt.dev/api-reference/models/CustomFilter)
- [DocumentMetadata](https://docs.velt.dev/api-reference/models/DocumentMetadata)
- [EditorAccessTimer](https://docs.velt.dev/api-reference/models/EditorAccessTimer)
- [null](https://docs.velt.dev/api-reference/models/FeatureTypes)
- [FlockOptions](https://docs.velt.dev/api-reference/models/FlockOptions)
- [LiveStateData](https://docs.velt.dev/api-reference/models/LiveStateData)
- [null](https://docs.velt.dev/api-reference/models/LiveStateDataMap)
- [null](https://docs.velt.dev/api-reference/models/Location)
- [LocationMetadata](https://docs.velt.dev/api-reference/models/LocationMetadata)
- [MediaPreviewConfig](https://docs.velt.dev/api-reference/models/MediaPreviewConfig)
- [null](https://docs.velt.dev/api-reference/models/Notification)
- [PageInfo](https://docs.velt.dev/api-reference/models/PageInfo)
- [PresenceUser](https://docs.velt.dev/api-reference/models/PresenceUser)
- [null](https://docs.velt.dev/api-reference/models/Recorder)
- [RecorderAnnotation](https://docs.velt.dev/api-reference/models/RecorderAnnotation)
- [RecorderData](https://docs.velt.dev/api-reference/models/RecorderData)
- [RewriterAnnotation](https://docs.velt.dev/api-reference/models/RewriterAnnotation)
- [SyncVideoPlayer](https://docs.velt.dev/api-reference/models/SyncVideoPlayer)
- [null](https://docs.velt.dev/api-reference/models/Toast)
- [null](https://docs.velt.dev/api-reference/models/Transcription)
- [null](https://docs.velt.dev/api-reference/models/User)
- [UserContactSelectedPayload](https://docs.velt.dev/api-reference/models/UserContactSelectedPayload)
- [UserContactUs](https://docs.velt.dev/api-reference/models/UserContactUs)
- [UserFeedback](https://docs.velt.dev/api-reference/models/UserFeedback)
- [Add Comment Annotations](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comment-annotations/add-comment-annotations)
- [Delete Comment Annotations](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comment-annotations/delete-comment-annotations)
- [Get Comment Annotations](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comment-annotations/get-comment-annotations)
- [Get Comment Annotations v2](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comment-annotations/get-comment-annotations-v2)
- [Update Comment Annotations](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comment-annotations/update-comment-annotations)
- [Add Comments](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comments/add-comments)
- [Delete Comments](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comments/delete-comments)
- [Get Comments](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comments/get-comments)
- [Update Comments](https://docs.velt.dev/api-reference/rest-apis/comments-feature/comments/update-comments)
- [Add Documents](https://docs.velt.dev/api-reference/rest-apis/documents/add-documents)
- [Delete Documents](https://docs.velt.dev/api-reference/rest-apis/documents/delete-documents)
- [Get Documents](https://docs.velt.dev/api-reference/rest-apis/documents/get-documents)
- [Get Documents v2](https://docs.velt.dev/api-reference/rest-apis/documents/get-documents-v2)
- [Update Access for Documents](https://docs.velt.dev/api-reference/rest-apis/documents/update-document-access)
- [Update Disabled State for Documents](https://docs.velt.dev/api-reference/rest-apis/documents/update-document-disable-state)
- [Update Documents](https://docs.velt.dev/api-reference/rest-apis/documents/update-documents)
- [Delete Data by Location](https://docs.velt.dev/api-reference/rest-apis/locations/delete-data-by-location): Delete all data associated with a specific location
- [Update Location](https://docs.velt.dev/api-reference/rest-apis/locations/update-location): Update a Location's metadata
- [Add Notifications](https://docs.velt.dev/api-reference/rest-apis/notifications/add-notifications)
- [Delete Notifications](https://docs.velt.dev/api-reference/rest-apis/notifications/delete-notifications)
- [Get Notifications](https://docs.velt.dev/api-reference/rest-apis/notifications/get-notifications)
- [Get Notifications v2](https://docs.velt.dev/api-reference/rest-apis/notifications/get-notifications-v2)
- [Update Notifications](https://docs.velt.dev/api-reference/rest-apis/notifications/update-notifications)
- [Add User Groups](https://docs.velt.dev/api-reference/rest-apis/organization-user-groups/add-groups)
- [Add Users to Groups](https://docs.velt.dev/api-reference/rest-apis/organization-user-groups/add-users-to-group)
- [Delete Users from Groups](https://docs.velt.dev/api-reference/rest-apis/organization-user-groups/delete-users-from-group)
- [Add Organizations](https://docs.velt.dev/api-reference/rest-apis/organizations/add-organizations)
- [Delete Organizations](https://docs.velt.dev/api-reference/rest-apis/organizations/delete-organizations)
- [Get Organizations](https://docs.velt.dev/api-reference/rest-apis/organizations/get-organizations)
- [Get Organizations v2](https://docs.velt.dev/api-reference/rest-apis/organizations/get-organizations-v2)
- [Update Disabled State for Organizations](https://docs.velt.dev/api-reference/rest-apis/organizations/update-organization-disable-state)
- [Update Organizations](https://docs.velt.dev/api-reference/rest-apis/organizations/update-organizations)
- [Add Users](https://docs.velt.dev/api-reference/rest-apis/users/add-users)
- [Delete All User Data (GDPR)](https://docs.velt.dev/api-reference/rest-apis/users/delete-all-user-data-gdpr): Remove All User data from Velt.
- [Delete Users](https://docs.velt.dev/api-reference/rest-apis/users/delete-users): Remove Users from an Organization or a Document.
- [Get Users](https://docs.velt.dev/api-reference/rest-apis/users/get-users)
- [Get Users v2](https://docs.velt.dev/api-reference/rest-apis/users/get-users-v2)
- [Update Users](https://docs.velt.dev/api-reference/rest-apis/users/update-users)
- [Customize Behavior](https://docs.velt.dev/async-collaboration/arrows/customize-behavior)
- [Arrows](https://docs.velt.dev/async-collaboration/arrows/overview)
- [Setup](https://docs.velt.dev/async-collaboration/arrows/setup)
- [Customize Behavior](https://docs.velt.dev/async-collaboration/comments-sidebar/customize-behavior)
- [Comments Sidebar](https://docs.velt.dev/async-collaboration/comments-sidebar/overview): Provide a toggleable sidebar to view and filter comments.
- [Setup](https://docs.velt.dev/async-collaboration/comments-sidebar/setup)
- [Customize Behavior](https://docs.velt.dev/async-collaboration/comments/customize-behavior/customize-behavior)
- [Comments Notifications](https://docs.velt.dev/async-collaboration/comments/notifications): There are several options to send notifications to your users.
- [Comments](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.
- [ChartJS Comments Setup](https://docs.velt.dev/async-collaboration/comments/setup/chart-comments-setup/chartjs)
- [Custom Charts Setup](https://docs.velt.dev/async-collaboration/comments/setup/chart-comments-setup/custom-charts)
- [Highcharts Comments Setup](https://docs.velt.dev/async-collaboration/comments/setup/chart-comments-setup/highcharts)
- [NivoCharts Comments Setup](https://docs.velt.dev/async-collaboration/comments/setup/chart-comments-setup/nivo-charts)
- [Freestyle Setup](https://docs.velt.dev/async-collaboration/comments/setup/freestyle)
- [Inbox Setup](https://docs.velt.dev/async-collaboration/comments/setup/inbox)
- [Inline Comments Setup](https://docs.velt.dev/async-collaboration/comments/setup/inline-comments)
- [Lottie Player Setup](https://docs.velt.dev/async-collaboration/comments/setup/lottie-player-setup)
- [Page Mode Setup](https://docs.velt.dev/async-collaboration/comments/setup/page)
- [Popover Setup](https://docs.velt.dev/async-collaboration/comments/setup/popover)
- [Stream Setup](https://docs.velt.dev/async-collaboration/comments/setup/stream)
- [Text Setup](https://docs.velt.dev/async-collaboration/comments/setup/text)
- [Tiptap Setup](https://docs.velt.dev/async-collaboration/comments/setup/tiptap)
- [Custom Video Player Setup](https://docs.velt.dev/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup): Use this guide to add collaboration into your own custom video player.
- [Prebuilt Video Player Setup](https://docs.velt.dev/async-collaboration/comments/setup/video-player-setup/video-player-setup): Use this guide if you want to set up a prebuilt video player from our SDK with collaborative features built in.
- [Comment Standalone Composer](https://docs.velt.dev/async-collaboration/comments/standalone-components/comment-composer/overview)
- [Setup](https://docs.velt.dev/async-collaboration/comments/standalone-components/comment-composer/setup)
- [Comment Pin](https://docs.velt.dev/async-collaboration/comments/standalone-components/comment-pin/overview)
- [Setup](https://docs.velt.dev/async-collaboration/comments/standalone-components/comment-pin/setup)
- [Customize Behavior](https://docs.velt.dev/async-collaboration/comments/standalone-components/comment-thread/customize-behavior)
- [Standalone Comment Thread](https://docs.velt.dev/async-collaboration/comments/standalone-components/comment-thread/overview)
- [Setup](https://docs.velt.dev/async-collaboration/comments/standalone-components/comment-thread/setup)
- [Customize Behavior](https://docs.velt.dev/async-collaboration/notifications/customize-behavior)
- [In-app Notifications](https://docs.velt.dev/async-collaboration/notifications/overview)
- [Setup](https://docs.velt.dev/async-collaboration/notifications/setup)
- [Inline Reactions](https://docs.velt.dev/async-collaboration/reactions/overview)
- [Setup](https://docs.velt.dev/async-collaboration/reactions/setup)
- [Customize Behavior](https://docs.velt.dev/async-collaboration/recorder/customize-behavior)
- [Recorder](https://docs.velt.dev/async-collaboration/recorder/overview): The Recorder allows your users to create audio, screen, and video recordings.
- [null](https://docs.velt.dev/async-collaboration/recorder/setup)
- [Customize Behavior](https://docs.velt.dev/async-collaboration/view-analytics/customize-behavior)
- [View Analytics](https://docs.velt.dev/async-collaboration/view-analytics/overview)
- [Setup](https://docs.velt.dev/async-collaboration/view-analytics/setup)
- [null](https://docs.velt.dev/get-started/overview)
- [Quickstart](https://docs.velt.dev/get-started/quickstart): Quickstart for React. For other frameworks like `vue`, `angular`, `svelte`, `vanilla js` etc. check out the setup guide.
- [Advanced Setup Options](https://docs.velt.dev/get-started/setup/advanced)
- [2. Authenticate](https://docs.velt.dev/get-started/setup/authenticate): Autheticate your logged in users with the SDK.
- [3. Initialize Document](https://docs.velt.dev/get-started/setup/initialize-document)
- [1. Install](https://docs.velt.dev/get-started/setup/install): Steps to integrate Velt into an existing app
- [AG Grid](https://docs.velt.dev/integrations/ag-grid)
- [null](https://docs.velt.dev/key-concepts/access-control/overview)
- [Set Document](https://docs.velt.dev/key-concepts/documents/set-document)
- [Use Multiple Locations at once](https://docs.velt.dev/key-concepts/locations/multiple-locations)
- [Remove Locations](https://docs.velt.dev/key-concepts/locations/remove-locations)
- [Set Location](https://docs.velt.dev/key-concepts/locations/set-location)
- [null](https://docs.velt.dev/key-concepts/organizations/setup)
- [null](https://docs.velt.dev/key-concepts/overview)
- [null](https://docs.velt.dev/key-concepts/users/contact-list)
- [null](https://docs.velt.dev/key-concepts/users/organization-user-groups)
- [null](https://docs.velt.dev/key-concepts/users/sign-in-user)
- [null](https://docs.velt.dev/key-concepts/users/sign-out-user)
- [Export Cord Data for Migration](https://docs.velt.dev/migration/cord-migration/export-cord-data-for-migration)
- [Overview](https://docs.velt.dev/migration/cord-migration/migration-process-overview)
- [Overview](https://docs.velt.dev/notifications/email/overview)
- [Customize Behavior](https://docs.velt.dev/realtime-collaboration/cursors/customize-behavior)
- [Overview](https://docs.velt.dev/realtime-collaboration/cursors/overview): Your users can view each other's cursors when interacting on the same document. This makes your app more alive. We handle the complexity of adapting the cursors to different screen sizes, differences in content etc.
- [null](https://docs.velt.dev/realtime-collaboration/cursors/setup)
- [Customize Behavior](https://docs.velt.dev/realtime-collaboration/flock-mode/customize-behavior)
- [Overview](https://docs.velt.dev/realtime-collaboration/flock-mode/overview): This is like Figma's follow along feature. Start a shared session in a click. One person is the leader, and whatever they do - like clicking, scrolling, or navigating - happens automatically on everyone else's screen.
- [Setup](https://docs.velt.dev/realtime-collaboration/flock-mode/setup)
- [Customize Behavior](https://docs.velt.dev/realtime-collaboration/huddle/customize-behavior)
- [Overview](https://docs.velt.dev/realtime-collaboration/huddle/overview): Enable slack-style effortless audio, video and screen sharing discussions inside your own product. It even comes with built in chat.
- [Setup](https://docs.velt.dev/realtime-collaboration/huddle/setup)
- [Customize Behavior](https://docs.velt.dev/realtime-collaboration/live-selection/customize-behavior)
- [Overview](https://docs.velt.dev/realtime-collaboration/live-selection/overview): Your users can see what part of the document others are interacting with in real-time.
- [null](https://docs.velt.dev/realtime-collaboration/live-selection/setup)
- [Overview](https://docs.velt.dev/realtime-collaboration/live-state-sync/overview): Allow users to sync state across forms in different clients
- [Redux Middleware](https://docs.velt.dev/realtime-collaboration/live-state-sync/redux-middleware)
- [null](https://docs.velt.dev/realtime-collaboration/live-state-sync/setup)
- [Customize Behavior](https://docs.velt.dev/realtime-collaboration/presence/customize-behavior)
- [Overview](https://docs.velt.dev/realtime-collaboration/presence/overview): Your users can see other users online on the document. This makes your app feel alive.
- [Setup](https://docs.velt.dev/realtime-collaboration/presence/setup)
- [Overview](https://docs.velt.dev/realtime-collaboration/single-editor-mode/overview): Lock down forms or settings dashboards so only a single editor can edit at once.
- [null](https://docs.velt.dev/realtime-collaboration/single-editor-mode/setup)
- [null](https://docs.velt.dev/realtime-collaboration/video-player-sync/overview)
- [Setup](https://docs.velt.dev/realtime-collaboration/video-player-sync/setup)
- [null](https://docs.velt.dev/release-notes/april-16-2024)
- [null](https://docs.velt.dev/release-notes/april-24-2024)
- [null](https://docs.velt.dev/release-notes/aug-12-2024)
- [null](https://docs.velt.dev/release-notes/aug-13-2024)
- [null](https://docs.velt.dev/release-notes/aug-14-2024)
- [null](https://docs.velt.dev/release-notes/aug-16-2024)
- [null](https://docs.velt.dev/release-notes/aug-21-2024)
- [null](https://docs.velt.dev/release-notes/aug-22-2024)
- [null](https://docs.velt.dev/release-notes/aug-30-2024)
- [null](https://docs.velt.dev/release-notes/aug-31-2024)
- [null](https://docs.velt.dev/release-notes/aug-6-2024)
- [null](https://docs.velt.dev/release-notes/aug-8-2024)
- [null](https://docs.velt.dev/release-notes/dec-28-2023)
- [null](https://docs.velt.dev/release-notes/feb-13-2024)
- [null](https://docs.velt.dev/release-notes/feb-20-2024)
- [null](https://docs.velt.dev/release-notes/feb-27-2024)
- [null](https://docs.velt.dev/release-notes/jan-14-2024)
- [null](https://docs.velt.dev/release-notes/july-02-2024)
- [null](https://docs.velt.dev/release-notes/july-03-2024)
- [null](https://docs.velt.dev/release-notes/july-04-2024)
- [null](https://docs.velt.dev/release-notes/july-09-2024)
- [null](https://docs.velt.dev/release-notes/june-10-2024)
- [null](https://docs.velt.dev/release-notes/june-24-2024)
- [null](https://docs.velt.dev/release-notes/june-29-2024)
- [null](https://docs.velt.dev/release-notes/june-30-2024)
- [null](https://docs.velt.dev/release-notes/june-6-2024)
- [null](https://docs.velt.dev/release-notes/march-14-2024)
- [null](https://docs.velt.dev/release-notes/march-5-2024)
- [null](https://docs.velt.dev/release-notes/may-10-2024)
- [null](https://docs.velt.dev/release-notes/may-17-2024)
- [null](https://docs.velt.dev/release-notes/may-23-2024)
- [null](https://docs.velt.dev/release-notes/may-24-2024)
- [null](https://docs.velt.dev/release-notes/may-29-2024)
- [null](https://docs.velt.dev/release-notes/nov-1-2024)
- [null](https://docs.velt.dev/release-notes/nov-12-2024)
- [null](https://docs.velt.dev/release-notes/nov-13-2024)
- [null](https://docs.velt.dev/release-notes/nov-15-2024)
- [null](https://docs.velt.dev/release-notes/nov-18-2024)
- [null](https://docs.velt.dev/release-notes/nov-20-2024)
- [null](https://docs.velt.dev/release-notes/nov-5-2024)
- [null](https://docs.velt.dev/release-notes/nov-6-2024)
- [null](https://docs.velt.dev/release-notes/nov-8-2024)
- [null](https://docs.velt.dev/release-notes/nov-9-2024)
- [null](https://docs.velt.dev/release-notes/oct-1-2024)
- [null](https://docs.velt.dev/release-notes/oct-10-2024)
- [null](https://docs.velt.dev/release-notes/oct-11-2024)
- [null](https://docs.velt.dev/release-notes/oct-14-2024)
- [null](https://docs.velt.dev/release-notes/oct-15-2024)
- [null](https://docs.velt.dev/release-notes/oct-16-2024)
- [null](https://docs.velt.dev/release-notes/oct-17-2024)
- [null](https://docs.velt.dev/release-notes/oct-24-2024)
- [null](https://docs.velt.dev/release-notes/oct-25-2024)
- [null](https://docs.velt.dev/release-notes/oct-29-2024)
- [null](https://docs.velt.dev/release-notes/oct-3-2024)
- [null](https://docs.velt.dev/release-notes/oct-30-2024)
- [null](https://docs.velt.dev/release-notes/oct-4-2024)
- [null](https://docs.velt.dev/release-notes/oct-7-2024)
- [null](https://docs.velt.dev/release-notes/oct-8-2024)
- [null](https://docs.velt.dev/release-notes/oct-9-2024)
- [null](https://docs.velt.dev/release-notes/sept-10-2024)
- [null](https://docs.velt.dev/release-notes/sept-12-2024)
- [null](https://docs.velt.dev/release-notes/sept-13-2024)
- [null](https://docs.velt.dev/release-notes/sept-14-2024)
- [null](https://docs.velt.dev/release-notes/sept-18-2024)
- [null](https://docs.velt.dev/release-notes/sept-20-2024)
- [null](https://docs.velt.dev/release-notes/sept-23-2024)
- [null](https://docs.velt.dev/release-notes/sept-24-2024)
- [null](https://docs.velt.dev/release-notes/sept-25-2024)
- [null](https://docs.velt.dev/release-notes/sept-26-2024)
- [null](https://docs.velt.dev/release-notes/sept-28-2024)
- [null](https://docs.velt.dev/release-notes/sept-3-2024)
- [null](https://docs.velt.dev/release-notes/sept-30-2024)
- [null](https://docs.velt.dev/release-notes/sept-4-2024)
- [null](https://docs.velt.dev/release-notes/sept-5-2024)
- [null](https://docs.velt.dev/release-notes/sept-7-2024)
- [Generating Auth Tokens](https://docs.velt.dev/security/auth-tokens)
- [null](https://docs.velt.dev/security/content-security-policy)
- [JWT Tokens](https://docs.velt.dev/security/jwt-tokens): Generate JWT Tokens for additional security
- [Proxy Server](https://docs.velt.dev/security/proxy-server)
- [Conditional Templates](https://docs.velt.dev/ui-customization/conditional-templates)
- [Dark Mode](https://docs.velt.dev/ui-customization/customize-css/dark-mode)
- [Remove Shadow DOM](https://docs.velt.dev/ui-customization/customize-css/remove-shadow-dom)
- [Themes](https://docs.velt.dev/ui-customization/customize-css/themes)
- [Use CSS Library](https://docs.velt.dev/ui-customization/customize-css/use-css-library)
- [Use Custom CSS](https://docs.velt.dev/ui-customization/customize-css/use-custom-css)
- [Replace component layout](https://docs.velt.dev/ui-customization/customize-layout/change-default-html)
- [Reorder Components](https://docs.velt.dev/ui-customization/customize-layout/change-order)
- [Overview](https://docs.velt.dev/ui-customization/customize-layout/overview)
- [Remove Components](https://docs.velt.dev/ui-customization/customize-layout/remove-existing)
- [Custom Button](https://docs.velt.dev/ui-customization/features/async/arrows/custom-button)
- [null](https://docs.velt.dev/ui-customization/features/async/arrows/parts)
- [Slots](https://docs.velt.dev/ui-customization/features/async/arrows/slots)
- [null](https://docs.velt.dev/ui-customization/features/async/arrows/variables)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comment-bubble/overview): This button shows the comment count and the author's avatar. This is used in Popover comments feature.
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comment-bubble/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-bubble/subcomponents/avatar): The subcomponent on the Comment Bubble that shows the User avatar
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-bubble/subcomponents/comments-count): The subcomponent on the Comment Bubble that shows the number of Comments made on a thread.
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/overview): The interface that appears when you try to read an existing Comment or make a new Comment.
- [Variants](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/pre-defined-variants)
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/all-comments): The subcomponent of the Comment Dialog that is used to show the All Comments button that opens the Comments Sidebar
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/approve): The subcomponent of the Comment Dialog that is used approve Comments in Moderator Mode
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/assignee-banner): The subcomponent of the Comment Dialog that is used assign a Comment as a task
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/autocomplete-chip-tooltip): The subcomponent of the Comment Dialog that represents the tooltip that appears when you hover over an Autocomplete Chip.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/autocomplete-option): The subcomponent of the Comment Dialog that represents the dropdown list that appears when you press an Autocomplete hotkey.
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/body/overview): The subcomponent of the Comment Dialog that is used to show all Comment Replies as well as the Comment Composer.
- [ThreadCard](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard): The subcomponent of the Body of the Comment Dialog that is used to show attachments added to a Comment reply.
- [ThreadCard Attachments](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard-attachments): The subcomponent of the Body of the Comment Dialog that is used to show attachments added to a Comment reply.
- [ThreadCard Options](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard-options): The subcomponent of the Body of the Comment Dialog that is used to show the options dropdown
- [ThreadCard Seen](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard-seen)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/composer/overview): The subcomponent of the Comment Dialog that is used to compose new Comment replies.
- [Composer Attachments](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/composer/subcomponents/composer-attachments): The subcomponent of the Comoposer of the Comment Dialog that is used to show attachments on a Comment that has been composed but hasn't been sent yet.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/composer/subcomponents/private-badge): The subcomponent of the Comment Dialog that is shown in the Composer when Private Mode is turned on.
- [Custom Annotation Dropdown](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/custom-annotation-dropdown): The subcomponent of the Comment Dialog that represents the custom annotation dropdown.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/ghost-banner): The subcomponent of the Comment Dialog that indicates if a Comment has become a Ghost Comment.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/header): The subcomponent of the Comment Dialog that represents the Header.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/navigation-button): Navigation button that appears on sidebar. Clicking on it will navigate to the comment.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/options-dropdown): The subcomponent of the Comment Dialog that represents the Options Dropdown
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/priority-dropdown): The subcomponent of the Comment Dialog that represents the Priority Dropdown
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/private-banner): The subcomponent of the Comment Dialog that is shown near the Header when the Comment is a Private Comment.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/reaction-pin): The subcomponent of the Comment Dialog that represents the the Reaction Pin that appears after a User selects a Reaction.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/reaction-pin-tooltip): The subcomponent of the Comment Dialog that represents the tooltip that appears when a User hovers over a Reaction
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/reaction-tool): The subcomponent of the Comment Dialog that represents the button used to add a Reaction
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/reactions-panel): The subcomponent of the Comment Dialog that represents the panel of all Reactions that have been added to a Comment
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/sign-in): The subcomponent of the Comment Dialog that represents the Sign In button that appears when a User is a Guest User
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/status-dropdown): The subcomponent of the Comment Dialog that represents the Status Dropdown
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/suggestion-action): The subcomponent of the Comment Dialog that represents the Accept or Reject button is Moderator Mode.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-dialog/subcomponents/upgrade): The subcomponent of the Comment Dialog that represents the Upgrade button.
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comment-pin/overview): The Pin that appears on the DOM when you place a Comment.
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comment-pin/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-pin/subcomponents/ghost-comment-indicator): The subcomponent on the Comment Pin that indicates whether the Comment is a Ghost Comment
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-pin/subcomponents/index): The subcomponent on the Comment Pin that indicates the index number of the Comment
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-pin/subcomponents/private-comment-indicator): The subcomponent on the Comment Pin that indicates whether the Comment is a Private Comment
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-pin/subcomponents/triangle): The subcomponent on the Comment Pin that appears as a triangle in the top right corner of a Popover Comment.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comment-pin/subcomponents/unread-comment-indicator): The subcomponent on the Comment Pin that indicates whether a Comment hasn't been read yet by the User.
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comment-player-timeline/styling)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comment-tool/overview): The button to add new comments.
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comment-tool/styling)
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comment-video-player/styling)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/overview)
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/custom-action-button)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/empty-placeholder): The subcomponent of the Comments Sidebar that represents the placeholder when there are no Comments
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/overview): The subcomponent of the Comments Sidebar that represents the filter that is used to filter what Comments appear in the Sidebar
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/category): The subcomponent of the Comments Sidebar Filter that represents the Category
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/close-button): The subcomponent of the Comments Sidebar Filter that represents the Close button
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/comment-type): The subcomponent of the Comments Sidebar Filter that represents the Comment Type filter
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/done-button): The subcomponent of the Comments Sidebar Filter that represents the Done Button
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/filter-item): Used to customize all the filter option items of the Comments Sidebar Filter at once
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/groupby): The subcomponent of the Comments Sidebar Filter that represents the Groupby filter option
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/location): The subcomponent of the Comments Sidebar Filter that represents the Location filter
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/people): The subcomponent of the Comments Sidebar Filter that represents the People filter
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/priority): The subcomponent of the Comments Sidebar Filter that represents the Priority filter
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/title): The subcomponent of the Comments Sidebar Filter that represents the Title
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/versions): The subcomponent of the Comments Sidebar Filter that represents the Version filter
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/focused-thread)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/overview): The subcomponent of the Comments Sidebar that represents the Header of the Sidebar
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/location-filter-dropdown/overview)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/minimal-action-dropdown/overview)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/minimal-filter-dropdown/overview)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/status/overview)
- [Content](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/status/subcomponents/content)
- [Trigger](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/status/subcomponents/trigger)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/list/overview): The subcomponent of the Comments Sidebar that represents the List of Comments in the Sidebar
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/list/subcomponents/dialog-container): You can customize the Comment Dialog that appears inside the Sidebar with this subcomponent
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/list/subcomponents/group): The subcomponent of the Comments Sidebar List that represents the Group
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/page-mode-composer): The subcomponent of the Comments Sidebar that represents the Composer that appears in Page Mode.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/reset-filter-button)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/sidebar-button/overview): The button that is used to open the Comments Sidebar panel.
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/sidebar-button/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/sidebar-button/subcomponents/comments-count): The subcomponent on the Sidebar Button that shows the total
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/sidebar-button/subcomponents/icon): The subcomponent on the Sidebar Button that shows the total
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/subcomponents/skeleton): The subcomponent of the Comments Sidebar that represents the Skeleton loader that appears when the Sidebar is first loading.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/comments-sidebar/variants)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/confirm-dialog/overview): The Confirmation Dialog that appears when you delete a comment annotation.
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/confirm-dialog/styling)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/inline-comments-section/overview): Components that appear when using Inline Comments
- [Variants](https://docs.velt.dev/ui-customization/features/async/comments/inline-comments-section/pre-defined-variants)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/inline-comments-section/subcomponents/panel/comment-count): The subcomponent of the Inline Comments Section that contains the Comment Count
- [null](https://docs.velt.dev/ui-customization/features/async/comments/inline-comments-section/subcomponents/panel/composer-container): The subcomponent of the Inline Comments Section that contains the Composer Container
- [null](https://docs.velt.dev/ui-customization/features/async/comments/inline-comments-section/subcomponents/panel/list): The subcomponent of the Inline Comments Section that contains the List
- [null](https://docs.velt.dev/ui-customization/features/async/comments/inline-comments-section/subcomponents/panel/overview): The subcomponent of the Inline Comments Section that contains the Panel
- [null](https://docs.velt.dev/ui-customization/features/async/comments/inline-comments-section/subcomponents/skeleton): The subcomponent of the Inline Comments Section that contains the Skeleton loader that appears when the Inline Comments Section is first loading.
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/multithread-comment-dialog/overview)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/persistent-comment-mode-banner/overview): The persistent comment mode banner that appears when persistent mode is enabled and user is adding a comment.
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-composer/overview)
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-composer/styling)
- [Variants](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-composer/variants)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-pin/overview): The Pin that appears on the DOM when you place a Comment.
- [Variants](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-pin/variants)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-thread/overview)
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-thread/styling)
- [Variants](https://docs.velt.dev/ui-customization/features/async/comments/standalone-components/comment-thread/variants)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-tool/overview): The Comment Tool that appears when you highlight some text.
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-tool/styling)
- [Overview](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-toolbar/overview): The Toolbar that appears when you highlight some text
- [Styling](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-toolbar/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-toolbar/subcomponents/comment-annotation): The subcomponent on the Text Comment Toolbar that is used to add a new Text Comment.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-toolbar/subcomponents/copywriter): The subcomponent on the Text Comment Toolbar that is used to rewrite text on the page using AI.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-toolbar/subcomponents/divider): The subcomponent on the Text Comment Toolbar that is used to divide other subcomponents in the UI using a thin line.
- [null](https://docs.velt.dev/ui-customization/features/async/comments/text-comment-toolbar/subcomponents/generic): The subcomponent on the Text Comment Toolbar that is used to query ChatGPT.
- [Overview](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/overview): The Notification Panel contains all notifications within the current organization. It appears when you click the notification tool or embed it directly on a page.
- [Styling](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/content/common-content-list): Common Content List component used within all the tab content sections. This renders the list of notifications. You can customize it for all tabs using this or customize it individually within each tab.
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/content/overview): This contains the main body of the Notifications Panel with the content of each tab.
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/content/subcomponents/all-tab-content): All Tab content that contains it's notifications.
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/content/subcomponents/documents-tab-content): Document tab content that contains it's notifications.
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/content/subcomponents/for-you-tab-content): For You tab content that contains it's notifications.
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/content/subcomponents/people-tab-content): People tab content that contains it's notifications.
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/header): This contains all the tabs that are present in the Notifications Panel Header
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/read-all-button): This button marks all notifications as read.
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-panel/subcomponents/title): The component that displays the title of the Notification Panel.
- [Overview](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-tool/overview): The button that opens or closes the notification panel.
- [Styling](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-tool/styling)
- [null](https://docs.velt.dev/ui-customization/features/async/notifications/notifications-tool/variant)
- [Overview](https://docs.velt.dev/ui-customization/features/async/reactions/overview): This component is used to render the reaction tool and all the reactions.
- [Styling](https://docs.velt.dev/ui-customization/features/async/reactions/styling)
- [Variants](https://docs.velt.dev/ui-customization/features/async/reactions/variants)
- [Create Your Own UI](https://docs.velt.dev/ui-customization/features/realtime/cursors/create-your-own-ui)
- [Parts](https://docs.velt.dev/ui-customization/features/realtime/cursors/parts)
- [Slots](https://docs.velt.dev/ui-customization/features/realtime/cursors/slots)
- [Variables](https://docs.velt.dev/ui-customization/features/realtime/cursors/variables)
- [null](https://docs.velt.dev/ui-customization/features/realtime/huddle/parts)
- [Slots](https://docs.velt.dev/ui-customization/features/realtime/huddle/slots)
- [null](https://docs.velt.dev/ui-customization/features/realtime/huddle/variables)
- [Overview](https://docs.velt.dev/ui-customization/features/realtime/live-selection)
- [Create Your Own UI](https://docs.velt.dev/ui-customization/features/realtime/presence/create-your-own-ui)
- [Parts](https://docs.velt.dev/ui-customization/features/realtime/presence/parts)
- [Variables](https://docs.velt.dev/ui-customization/features/realtime/presence/variables)
- [Overview](https://docs.velt.dev/ui-customization/overview)
- [Overview](https://docs.velt.dev/ui-customization/setup)
- [Template Variables](https://docs.velt.dev/ui-customization/template-variables)
- [Variants](https://docs.velt.dev/ui-customization/variants)
- [Comments Webhooks](https://docs.velt.dev/webhooks/comments-webhooks)
- [Huddle Webhooks](https://docs.velt.dev/webhooks/huddle-webhooks)
- [Overview](https://docs.velt.dev/webhooks/overview)


## Optional

- [Examples](https://velt.dev/examples)


# null



## getAllCommentAnnotations()

Subscribe to comments on the current document.

*   **Signature**: `getAllCommentAnnotations(documentId?: string, location?: object)`
*   **Params**: `documentId?: string, location?: object`
*   **Returns**: `Observable<CommentAnnotation[] | null>`

## deleteSelectedComment()

To delete selected comments.

*   **Signature**: `deleteSelectedComment()`
*   **Params**: none
*   **Returns**: `Promise<any>`

## selectCommentByAnnotationId()

To select comment by annotation ID.

*   **Signature**: `selectCommentByAnnotationId(annotationId?: string)`
*   **Params**: `annotationId`
*   **Returns**: void

## enableAreaComment()

To enable area comment.

*   **Signature**: `enableAreaComment()`
*   **Params**: none
*   **Returns**: void

## disableAreaComment()

To disable area comment.

*   **Signature**: `disableAreaComment()`
*   **Params**: none
*   **Returns**: void

## enableTextComments()

To enable text comment selection.

*   **Signature**: `enableTextComments()`
*   **Params**: none
*   **Returns**: `any`

## disableTextComments()

To disable text comment selection.

*   **Signature**: `disableTextComments()`
*   **Params**: none
*   **Returns**: `any`

## allowedElementIds()

To allow text selection in specific elements only.

*   **Signature**: `allowedElementIds(elementIds: string[])`
*   **Params**: `elementIds: string[]`
*   **Returns**: `any`

## allowedElementClassNames()

To allow adding comments in specific elements only.

*   **Signature**: `allowedElementClassNames(classNames: string[])`
*   **Params**: `classNames: string[]`
*   **Returns**: `any`

## allowedElementQuerySelectors()

To allow adding comments in specific elements only.

*   **Signature**: `allowedElementQuerySelectors(querySelectors: string[])`
*   **Params**: `querySelectors: string[]`
*   **Returns**: `any`

## updateCommentDialogPosition()

To update comment dialog position.

*   **Signature**: `updateCommentDialogPosition()`
*   **Params**: none
*   **Returns**: void

## enableFloatingCommentDialog()

To enable floating comment dialog.

*   **Signature**: `enableFloatingCommentDialog()`
*   **Params**: none
*   **Returns**: `any`

## disableFloatingCommentDialog()

To disable floating comment dialog.

*   **Signature**: `disableFloatingCommentDialog()`
*   **Params**: none
*   **Returns**: `any`

## attachComment()

To add comments on specific elements.

*   **Signature**: `attachComment(elementId: string)`
*   **Params**: `elementId: string`
*   **Returns**: `any`

## openCommentSidebar()

To open comment sidebar.

*   **Signature**: `openCommentSidebar()`
*   **Params**: none
*   **Returns**: `any`

## closeCommentSidebar()

To close comment sidebar.

*   **Signature**: `closeCommentSidebar()`
*   **Params**: none
*   **Returns**: `any`

## toggleCommentSidebar()

To toggle comment sidebar.

*   **Signature**: `toggleCommentSidebar()`
*   **Params**: none
*   **Returns**: `any`

## enableModeratorMode()

To enable moderator mode.

*   **Signature**: `enableModeratorMode()`
*   **Params**: none
*   **Returns**: `any`

## disableModeratorMode()

To disable moderator mode.

*   **Signature**: `disableModeratorMode()`
*   **Params**: none
*   **Returns**: `any`

## enableStreamMode()

To enable stream mode.

*   **Signature**: `enableStreamMode()`
*   **Params**: none
*   **Returns**: `any`

## disableStreamMode()

To disable stream mode.

*   **Signature**: `disableStreamMode()`
*   **Params**: none
*   **Returns**: `any`

## enableSignInButton()

To show sign in button in comments if user is signed out.

*   **Signature**: `enableSignInButton()`
*   **Params**: none
*   **Returns**: `any`

## disableSignInButton()

To hide sign in button in comments if user is signed out.

*   **Signature**: `disableSignInButton()`
*   **Params**: none
*   **Returns**: `any`

## enableUpgradeButton()

To enable upgrade button in comments when plan is expired.

*   **Signature**: `enableUpgradeButton()`
*   **Params**: none
*   **Returns**: `any`

## disableUpgradeButton()

To disable upgrade button in comments when plan is expired.

*   **Signature**: `disableUpgradeButton()`
*   **Params**: none
*   **Returns**: `any`

## onCommentModeChange()

Subscribe to comment mode change.

*   **Signature**: `onCommentModeChange()`
*   **Params**: none
*   **Returns**: `Observable<boolean>`

## enableAttachments()

Enable attachments feature in comments.

*   **Signature**: `enableAttachments()`
*   **Params**: none
*   **Returns**: `any`

## disableAttachments()

Disable attachments feature in comments.

*   **Signature**: `disableAttachments()`
*   **Params**: none
*   **Returns**: `any`

## isUserGlobalContact()

Get if user is part of global contact or not.

*   **Signature**: `isUserGlobalContact()`
*   **Params**: none
*   **Returns**: `Observable<boolean>`

## enableDeviceInfo()

Enable device info in comments.

*   **Signature**: `enableDeviceInfo()`
*   **Params**: none
*   **Returns**: `any`

## disableDeviceInfo()

Disable device info in comments.

*   **Signature**: `disableDeviceInfo()`
*   **Params**: none
*   **Returns**: `any`

## enableCommentMode()

Enable comment mode to add comments.

*   **Signature**: `enableCommentMode()`
*   **Params**: none
*   **Returns**: `any`

## disableCommentMode()

Disable comment mode.

*   **Signature**: `disableCommentMode()`
*   **Params**: none
*   **Returns**: `any`

## enablePersistentCommentMode()

Enable persistent comment mode.

*   **Signature**: `enablePersistentCommentMode()`
*   **Params**: none
*   **Returns**: `any`

## disablePersistentCommentMode()

Disable persistent comment mode.

*   **Signature**: `disablePersistentCommentMode()`
*   **Params**: none
*   **Returns**: `any`

## enableCommentIndex()

To show comment number.

*   **Signature**: `enableCommentIndex()`
*   **Params**: none
*   **Returns**: `any`

## disableCommentIndex()

To hide comment number.

*   **Signature**: `disableCommentIndex()`
*   **Params**: none
*   **Returns**: `any`

## enablePopoverMode()

To enable popover mode.

*   **Signature**: `enablePopoverMode()`
*   **Params**: none
*   **Returns**: `any`

## disablePopoverMode()

To disable popover mode.

*   **Signature**: `disablePopoverMode()`
*   **Params**: none
*   **Returns**: `any`

## enablePopoverTriangleComponent()

To show triangle in popover mode.

*   **Signature**: `enablePopoverTriangleComponent()`
*   **Params**: none
*   **Returns**: `any`

## disablePopoverTriangleComponent()

To hide triangle in popover mode.

*   **Signature**: `disablePopoverTriangleComponent()`
*   **Params**: none
*   **Returns**: `any`

## enableDialogOnHover()

To enable dialog on hover.

*   **Signature**: `enableDialogOnHover()`
*   **Params**: none
*   **Returns**: `any`

## disableDialogOnHover()

To disable dialog on hover.

*   **Signature**: `disableDialogOnHover()`
*   **Params**: none
*   **Returns**: `any`

## enableDialogOnTargetElementClick()

To enable feature to show dialog on target element click.

*   **Signature**: `enableDialogOnTargetElementClick()`
*   **Params**: none
*   **Returns**: `any`

## disableDialogOnTargetElementClick()

To disable feature to show dialog on target element click.

*   **Signature**: `disableDialogOnTargetElementClick()`
*   **Params**: none
*   **Returns**: `any`

## enablePriority()

To enable feature to set priority on comments.

*   **Signature**: `enablePriority()`
*   **Params**: none
*   **Returns**: `any`

## disablePriority()

To disable feature to set priority on comments.

*   **Signature**: `disablePriority()`
*   **Params**: none
*   **Returns**: `any`

## enableStatus()

To enable the feature to set status on comments.

*   **Signature**: `enableStatus()`
*   **Params**: none
*   **Returns**: `any`

## disableStatus()

To disable the feature to set status on comments.

*   **Signature**: `disableStatus()`
*   **Params**: none
*   **Returns**: `any`

## enableResolveButton()

To enable the feature to show the resolve button.

*   **Signature**: `enableResolveButton()`
*   **Params**: none
*   **Returns**: `any`

## disableResolveButton()

To disable the feature to show the resolve button.

*   **Signature**: `disableResolveButton()`
*   **Params**: none
*   **Returns**: `any`

## enableGhostComments()

To enable the feature to show ghost comments.

*   **Signature**: `enableGhostComments()`
*   **Params**: none
*   **Returns**: `any`

## disableGhostComments()

To disable the feature to show ghost comments.

*   **Signature**: `disableGhostComments()`
*   **Params**: none
*   **Returns**: `any`

## enableGhostCommentsIndicator()

To enable the feature to show ghost comments message in comment dialog and comment sidebar.

*   **Signature**: `enableGhostCommentsIndicator()`
*   **Params**: none
*   **Returns**: `any`

## disableGhostCommentsIndicator()

To disable the feature to show ghost comments message in comment dialog and comment sidebar.

*   **Signature**: `disableGhostCommentsIndicator()`
*   **Params**: none
*   **Returns**: `any`

## setCustomStatus()

Sets custom status filters.

*   **Signature**: `setCustomStatus(statuses: CustomStatus[])`
*   **Params**: `statuses: CustomStatus[]`
*   **Returns**: `void`

## setCustomPriority()

Sets custom priority filters.

*   **Signature**: `setCustomPriority(priorities: CustomPriority[])`
*   **Params**: `priorities: CustomPriority[]`
*   **Returns**: `void`

## setCustomCategory()

Sets custom categories filters.

*   **Signature**: `setCustomCategory(categories: CustomCategory[])`
*   **Params**: `categories: CustomCategory[]`
*   **Returns**: `void`

## enableInboxMode()

To enable inbox mode.

*   **Signature**: `enableInboxMode()`
*   **Params**: none
*   **Returns**: `any`

## disableInboxMode()

To disable inbox mode.

*   **Signature**: `disableInboxMode()`
*   **Params**: none
*   **Returns**: `any`

## enableAutoCategorize()

To enable auto categorize feature.

*   **Signature**: `enableAutoCategorize()`
*   **Params**: none
*   **Returns**: `any`

## disableAutoCategorize()

To disable auto categorize feature.

*   **Signature**: `disableAutoCategorize()`
*   **Params**: none
*   **Returns**: `any`

## enableDarkMode()

To enable dark mode in comments.

*   **Signature**: `enableDarkMode()`
*   **Params**: none
*   **Returns**: `any`

## disableDarkMode()

To disable dark mode in comments.

*   **Signature**: `disableDarkMode()`
*   **Params**: none
*   **Returns**: `any`

## setContextProvider()

Sets the comment context provider.

*   **Signature**: `setContextProvider(provider: (documentId: string, location?: any) => any)`
*   **Params**: `provider: (documentId: string, location?: any) => any`
*   **Returns**: `void`

## enableSuggestionMode()

To enable suggestion mode.

*   **Signature**: `enableSuggestionMode()`
*   **Params**: none
*   **Returns**: `any`

## disableSuggestionMode()

To disable suggestion mode.

*   **Signature**: `disableSuggestionMode()`
*   **Params**: none
*   **Returns**: `any`

## enableMobileMode()

To enable mobile mode.

*   **Signature**: `enableMobileMode()`
*   **Params**: none
*   **Returns**: `any`

## disableMobileMode()

To disable mobile mode.

*   **Signature**: `disableMobileMode()`
*   **Params**: none
*   **Returns**: `any`

## enableInlineCommentMode()

To enable inline comment mode.

*   **Signature**: `enableInlineCommentMode()`
*   **Params**: none
*   **Returns**: `any`

## disableInlineCommentMode()

To disable inline comment mode.

*   **Signature**: `disableInlineCommentMode()`
*   **Params**: none
*   **Returns**: `any`

## enableMinimap()

To enable minimap.

*   **Signature**: `enableMinimap()`
*   **Params**: none
*   **Returns**: `any`

## disableMinimap()

To disable minimap.

*   **Signature**: `disableMinimap()`
*   **Params**: none
*   **Returns**: `any`

## showCommentsOnDom()

To show comments on DOM.

*   **Signature**: `showCommentsOnDom()`
*   **Params**: none
*   **Returns**: `any`

## hideCommentsOnDom()

To hide comments on DOM.

*   **Signature**: `hideCommentsOnDom()`
*   **Params**: none
*   **Returns**: `any`

## enableCommentTool()

To enable comment tool.

*   **Signature**: `enableCommentTool()`
*   **Params**: none
*   **Returns**: `any`

## disableCommentTool()

To disable comment tool.

*   **Signature**: `disableCommentTool()`
*   **Params**: none
*   **Returns**: `any`

## setTotalMediaLength()

To set total media length.

*   **Signature**: `setTotalMediaLength(totalMediaLength: number)`
*   **Params**: `totalMediaLength: number`
*   **Returns**: `void`

## onCommentAdd()

To get documentId, location, and set context data when a comment is added.

*   **Signature**: `onCommentAdd()`
*   **Params**: none
*   **Returns**: `Observable<any>`

## onCommentUpdate()

To get data when a comment is updated.

*   **Signature**: `onCommentUpdate()`
*   **Params**: none
*   **Returns**: `Observable<any>`

## addCommentOnSelectedText()

To add a comment on selected text.

*   **Signature**: `addCommentOnSelectedText()`
*   **Params**: none
*   **Returns**: `void`

## enableSidebarUrlNavigation()

To enable navigation when a comment is clicked in the sidebar.

*   **Signature**: `enableSidebarUrlNavigation()`
*   **Params**: none
*   **Returns**: `void`

## disableSidebarUrlNavigation()

To disable navigation when a comment is clicked in the sidebar.

*   **Signature**: `disableSidebarUrlNavigation()`
*   **Params**: none
*   **Returns**: `void`

## enableSidebarButtonOnCommentDialog()

To enable the sidebar button on the comment dialog.

*   **Signature**: `enableSidebarButtonOnCommentDialog()`
*   **Params**: none
*   **Returns**: `void`

## disableSidebarButtonOnCommentDialog()

To disable the sidebar button on the comment dialog.

*   **Signature**: `disableSidebarButtonOnCommentDialog()`
*   **Params**: none
*   **Returns**: `void`

## onSidebarButtonOnCommentDialogClick()

To detect a click on the sidebar button on the comment dialog.

*   **Signature**: `onSidebarButtonOnCommentDialogClick()`
*   **Params**: none
*   **Returns**: `Observable<any>`

## enableReactions()

To enable reactions in comments.

*   **Signature**: `enableReactions()`
*   **Params**: none
*   **Returns**: `void`

## disableReactions()

To disable reactions in comments.

*   **Signature**: `disableReactions()`
*   **Params**: none
*   **Returns**: `void`

## setRecordings()

To set allowed recordings in comments.

*   **Signature**: `setRecordings(allowedRecordings: string | string[])`
*   **Params**: `allowedRecordings: string | string[]`
*   **Returns**: `void`

## addManualComment()

To add manual comment with context.

*   **Signature**: `addManualComment(config: ManualCommentAnnotationConfig)`
*   **Params**: `config: ManualCommentAnnotationConfig`
*   **Returns**: `void`

## addCommentOnElement()

To manually add a comment on an element.

*   **Signature**: `addCommentOnElement(data: CommentOnElementConfig)`
*   **Params**: `data: CommentOnElementConfig`
*   **Returns**: `void`

## enablePrivateCommentMode()

To enable private comment mode to add private comments. This mode can be enabled for admin users only.

*   **Signature**: `enablePrivateCommentMode()`
*   **Params**: none
*   **Returns**: `void`

## disablePrivateCommentMode()

To disable private comment mode.

*   **Signature**: `disablePrivateCommentMode()`
*   **Params**: none
*   **Returns**: `void`

## enableScrollToComment()

To enable scroll to comment.

*   **Signature**: `enableScrollToComment()`
*   **Params**: none
*   **Returns**: `void`

## disableScrollToComment()

To disable scroll to comment.

*   **Signature**: `disableScrollToComment()`
*   **Params**: none
*   **Returns**: `void`

## enableUserMentions()

To enable user mentions in comments.

*   **Signature**: `enableUserMentions()`
*   **Params**: none
*   **Returns**: `void`

## disableUserMentions()

To disable user mentions in comments.

*   **Signature**: `disableUserMentions()`
*   **Params**: none
*   **Returns**: `void`

## setCommentSidebarFilters()

To apply filters on comment sidebar.

*   **Signature**: `setCommentSidebarFilters(filters: any)`
*   **Params**: `filters: any`
*   **Returns**: `void`

## setPinCursorImage()

To set custom cursor for comment.

*   **Signature**: `setPinCursorImage(imageString: string)`
*   **Params**: `imageString`
*   **Returns**: `void`

## enableCommentPinHighlighter()

To enable comment pin highlighter.

*   **Signature**: `enableCommentPinHighlighter()`
*   **Params**: none
*   **Returns**: `void`

## disableCommentPinHighlighter()

To disable comment pin highlighter.

*   **Signature**: `disableCommentPinHighlighter()`
*   **Params**: none
*   **Returns**: `void`

## enableDeleteOnBackspace()

To enable deleting comment on backspace.

*   **Signature**: `enableDeleteOnBackspace()`
*   **Params**: none
*   **Returns**: `void`

## disableDeleteOnBackspace()

To disable deleting comment on backspace.

*   **Signature**: `disableDeleteOnBackspace()`
*   **Params**: none
*   **Returns**: `void`

## enableHotkey()

To enable hotkey.

*   **Signature**: `enableHotkey()`
*   **Params**: none
*   **Returns**: `void`

## disableHotkey()

To disable hotkey.

*   **Signature**: `disableHotkey()`
*   **Params**: none
*   **Returns**: `void`

## createCustomListDataOnComment()

To create custom list data on comment.

*   **Signature**: `createCustomListDataOnComment(customListDataOnComment)`
*   **Params**: `customListDataOnComment`
*   **Returns**: `void`

## createCustomListDataOnAnnotation()

To create custom list data on annotations.

*   **Signature**: `createCustomListDataOnAnnotation(customChipDropdownData)`
*   **Params**: `customChipDropdownData`
*   **Returns**: `void`


# null



## getOnlineUsersOnCurrentDocument()

Subscribe to cursors of all online users who are either active or inactive on the current document.

*   **Signature**: `getOnlineUsersOnCurrentDocument: () => Observable<CursorUser[] | null>`
*   **Params**: none
*   **Returns**: `Observable<CursorUser[] | null>`

## setInactivityTime()

This method sets the inactivity time in milliseconds.

*   **Signature**: `setInactivityTime: (milliseconds: number) => void;`
*   **Params**: `milliseconds: number`
*   **Returns**: `void`

## allowedElementIds()

To allow cursors in specific elements only.

*   **Signature**: `allowedElementIds: (elementIds: string[]) => any`
*   **Params**: `elementIds: string[]`
*   **Returns**: `any`


# null



## getLiveStateData()

Retrieves live state data as an observable based on the provided ID.

*   **Signature**: `getLiveStateData(liveStateDataId?: string): Observable<any>`
*   **Params**: `liveStateDataId?: string`
*   **Returns**: `Observable<any>`

## setLiveStateData()

Sets live state data for the provided ID and data.

*   **Signature**: `setLiveStateData(liveStateDataId: string, liveStateData: any): any`
*   **Params**: `liveStateDataId: string , liveStateData: any`
*   **Returns**: `any`

## enableSingleEditorMode()

Enables the single editor mode with an optional configuration.

*   **Signature**: `enableSingleEditorMode(config?: SingleEditorConfig): void`
*   **Params**: `config?: SingleEditorConfig`
*   **Returns**: `void`

## disableSingleEditorMode()

Disables the single editor mode.

*   **Signature**: `disableSingleEditorMode(): void`
*   **Params**: none
*   **Returns**: `void`

## isUserEditor()

Checks if the current user is an editor. Returns an observable.

*   **Signature**: `isUserEditor(): Observable<UserEditorAccess | null>`
*   **Params**: none
*   **Returns**: `Observable<UserEditorAccess | null>`

## getEditor()

Retrieves the current editor information.

*   **Signature**: `getEditor(): Observable<User | null>`
*   **Params**: none
*   **Returns**: `Observable<User | null>`

## setUserAsEditor()

Sets the current user as an editor.

*   **Signature**: `setUserAsEditor(): void`
*   **Params**: none
*   **Returns**: `void`

## resetUserAccess()

Resets the user access.

*   **Signature**: `resetUserAccess(): void`
*   **Params**: none
*   **Returns**: `void`

## singleEditorModeContainerIds()

Disables elements inside specific elements only when single editor mode is on.

*   **Signature**: `singleEditorModeContainerIds(elementIds: string[]): void`
*   **Params**: `elementIds: string[]`
*   **Returns**: `void`

## enableAutoSyncState()

Enables the autosync state feature.

*   **Signature**: `enableAutoSyncState(): void`
*   **Params**: none
*   **Returns**: `void`

## disableAutoSyncState()

Disables the autosync state feature.

*   **Signature**: `disableAutoSyncState(): void`
*   **Params**: none
*   **Returns**: `void`

## requestEditorAccess()

Initiates a request for editor access.

*   **Signature**: `requestEditorAccess(): Observable<boolean | null>`
*   **Params**: none
*   **Returns**: `Observable<boolean | null>`

## isEditorAccessRequested()

Checks if editor access has been requested.

*   **Signature**: `isEditorAccessRequested(): Observable<{ requestStatus: string, requestedBy: User } | null>`
*   **Params**: none
*   **Returns**: `Observable<{ requestStatus: string, requestedBy: User } | null>`

## acceptEditorAccessRequest()

Accepts an editor access request.

*   **Signature**: `acceptEditorAccessRequest(): void`
*   **Params**: none
*   **Returns**: `void`

## rejectEditorAccessRequest()

Rejects an editor access request.

*   **Signature**: `rejectEditorAccessRequest(): void`
*   **Params**: none
*   **Returns**: `void`

## cancelEditorAccessRequest()

Cancels an editor access request.

*   **Signature**: `cancelEditorAccessRequest(): void`
*   **Params**: none
*   **Returns**: `void`

## editCurrentTab()

Edits the current tab.

*   **Signature**: `editCurrentTab(): void`
*   **Params**: none
*   **Returns**: `void`

## setEditorAccessTimeout()

Sets a timeout for editor access. (in milliseconds)

*   **Signature**: `setEditorAccessTimeout(timeout: number): void`
*   **Params**: `timeout: number`
*   **Returns**: `void`

## enableEditorAccessTransferOnTimeOut()

Enables the transfer of editor access on timeout.

*   **Signature**: `enableEditorAccessTransferOnTimeOut(): void`
*   **Params**: none
*   **Returns**: `void`

## disableEditorAccessTransferOnTimeOut()

Disables the transfer of editor access on timeout.

*   **Signature**: `disableEditorAccessTransferOnTimeOut(): void`
*   **Params**: none
*   **Returns**: `void`

## enableDefaultSingleEditorUI()

Enables the default UI for single editor mode.

*   **Signature**: `enableDefaultSingleEditorUI(): void`
*   **Params**: none
*   **Returns**: `void`

## disableDefaultSingleEditorUI()

Disables the default UI for single editor mode.

*   **Signature**: `disableDefaultSingleEditorUI(): void`
*   **Params**: none
*   **Returns**: `void`


# null



## setMaxDays()

To set maximum days within the notification tool and notification element.

*   **Signature**: `setMaxDays(days)`
*   **Params**: `days`
*   **Returns**: void


# null



## getOnlineUsersOnCurrentDocument()

Subscribe to a list of all online users who are either active or inactive on the current document. You can also use this find how many users are online on the current document and show them custom messages.

Example:

```jsx
const presenceElement = client.getPresenceElement();
presenceElement.getOnlineUsersOnCurrentDocument();
```

*   **Signature**: `getOnlineUsersOnCurrentDocument: () => Observable<PresenceUser[] | null>`

*   **Params**: none

*   **Returns**: `Observable<PresenceUser[] | null>`

## setInactivityTime()

By default if the user is inactive for >5 minutes, we mark them offline. By inactive we mean they haven't moved their mouse or haven't made any keyboard event. You can configure this default threshold using this method.

Example:

```jsx
const presenceElement = client.getPresenceElement();
presenceElement.setInactivityTime();
```

*   **Signature**: `setInactivityTime: (milliseconds: number) => void`

*   **Params**: `milliseconds: number`

*   **Returns**: `void`

## enableFollowAlongMode()

This method enables Follow Along Mode.

Example:

```jsx
const presenceElement = client.getPresenceElement();
presenceElement.enableFollowAlongMode();
```

*   **Signature**: `enableFollowAlongMode: (useHistoryAPI: boolean) => any`

*   **Params**: `useHistoryAPI: boolean`

*   **Returns**: `any`

## disableFollowAlongMode()

This method disables Follow Along Mode.

Example:

```jsx
const presenceElement = client.getPresenceElement();
presenceElement.disableFollowAlongMode();
```

*   **Signature**: `disableFollowAlongMode: () => any`

*   **Params**: none

*   **Returns**:  `any`


# null



## initRecording()

This method initializes recording.

Example:

```jsx
const recorderElement = client.getRecorderElement();
recorderElement.initRecording(type: string, panelId?: string);
```

*   **Signature**: `(type: string, panelId?: string) => any`

*   **Params**: `type: string, panelId?: string`

*   **Returns**: `any`

## onRecordedData()

This method listens to recorded data.

Example:

```jsx
const recorderElement = client.getRecorderElement();
recorderElement.onRecordedData((id,tag) => {
    console.log(id,tag)
});
```

*   **Signature**: `() => Observable<any>`

*   **Params**: none

*   **Returns**: `any`


# null



## enableRewriter()

This method enables the rewriter.

Example:

```jsx
const rewriterElement = client.getRewriterElement();
rewriterElement.enableRewriter();
```

*   **Signature**: `enableRewriter() => void`

*   **Params**: none

*   **Returns**: `void`

## disableRewriter()

This method disables the rewriter.

Example:

```jsx
const rewriterElement = client.getRewriterElement();
rewriterElement.disableRewriter();
```

*   **Signature**: `disableRewriter() => void`

*   **Params**: none

*   **Returns**: void


# null



## enableLiveSelection()

This method enables live selection mode.

Example:

```jsx
const liveSelectionElement = client.getSelectionElement();
liveSelectionElement.enableLiveSelection();
```

*   **Signature**: `enableLiveSelection() => void`

*   **Params**: none

*   **Returns**: `void`

## disableLiveSelection()

This method disables live selection mode.

Example:

```jsx
const liveSelectionElement = client.getSelectionElement();
liveSelectionElement.disableLiveSelection();
```

*   **Signature**: `disableLiveSelection() => void`
*   **Params**: none
*   **Returns**: `void`


# null



## initConfig()

Used to set up initial configurations for the Velt SDK.

*   **Signature**: `initConfig(apiKey: string, config?: Config)`
*   **Params**: `apiKey: string, config?: Config`
*   **Returns**: none

## identify()

Used to authenticate the client's user with the Velt SDK.

*   **Signature**: `identify(user: User, userOptions?: UserOptions)`
*   **Params**: `user: User, userOptions?: UserOptions`
*   **Returns**: `Promise<unknown>`

## setDocumentId()

Tell us the unique ID of the current document/resource on which you want to enable collaboration.

*   **Signature**: `setDocumentId(id: string)`
*   **Params**: `id: string`
*   **Returns**: none

## unsetDocumentId()

You can unset the Document Id to pause the Velt SDK functions.

*   **Signature**: `unsetDocumentId()`
*   **Params**: none
*   **Returns**: none

## setLocation()

Tell us the custom params of the current document/resource to identify sub document inside a document.

*   **Signature**: `setLocation(params: Location, appendLocation?: boolean)`
*   **Params**: `params: Location, appendLocation?: boolean`
*   **Returns**: none

## removeLocation()

To remove location from a User.

*   **Signature**: `removeLocation(location?: Location)`
*   **Params**: `location?: Location`
*   **Returns**: none

## setScrollableElementsIds()

Tell us about the scrollable document ids to keep track on its scroll changes.

*   **Signature**: `setScrollableElementsIds(ids: string[])`
*   **Params**: `ids: string[]`
*   **Returns**: none

## removeScrollableElementsIds()

To remove document params from a User.

*   **Signature**: `removeScrollableElementsIds()`
*   **Params**: none
*   **Returns**: none

## getPresenceElement()

Get the Presence Element Object to access the raw presence data.

*   **Signature**: `getPresenceElement()`
*   **Params**: none
*   **Returns**: `PresenceElement`

## getCursorElement()

Get the Cursor Element Object to access the raw cursor data.

*   **Signature**: `getCursorElement()`
*   **Params**: none
*   **Returns**: `CursorElement`

## getCommentElement()

Get the Comment Element Object to access the raw comment data.

*   **Signature**: `getCommentElement()`
*   **Params**: none
*   **Returns**: `CommentElement`

## getTagElement()

Get the Tag Pin Annotation Object to access the raw tag data.

*   **Signature**: `getTagElement()`
*   **Params**: none
*   **Returns**: `TagElement`

## getSelectionElement()

Get the Selection Object to enable/disable the feature.

*   **Signature**: `getSelectionElement()`
*   **Params**: none
*   **Returns**: `SelectionElement`

## getRecorderElement()

Get the Recorder Object.

*   **Signature**: `getRecorderElement()`
*   **Params**: none
*   **Returns**: `RecorderElement`

## getContactElement()

Get the Contact Object.

*   **Signature**: `getContactElement()`
*   **Params**: none
*   **Returns**: `ContactElement`

## getRewriterElement()

Get the Rewriter Object.

*   **Signature**: `getRewriterElement()`
*   **Params**: none
*   **Returns**: `RewriterElement`

## getLiveStateSyncElement()

Get the LiveStateSync Object.

*   **Signature**: `getLiveStateSyncElement()`
*   **Params**: none
*   **Returns**: `LiveStateSyncElement`

## getArrowElement()

Get the Arrow Object.

*   **Signature**: `getArrowElement()`
*   **Params**: none
*   **Returns**: `ArrowElement`

## signOutUser()

To sign out a user.

*   **Signature**: `signOutUser()`
*   **Params**: none
*   **Returns**: `any`

## disableFeatures()

Provide a list of features to disable. Provide an empty array to enable all the features.

*   **Signature**: `disableFeatures(features: Array<FeatureType>)`
*   **Params**: `features: Array<FeatureType>`
*   **Returns**: none

## addLocation()

Add location to show comments, tags, recorders etc. for provided location also.

*   **Signature**: `addLocation(location: any)`
*   **Params**: `location: any`
*   **Returns**: none

## isUserAllowed\$()

To check if user is allowed in provided document or not.

*   **Signature**: `isUserAllowed$()`
*   **Params**: none
*   **Returns**: `Observable<boolean>`

## getUserRole\$()

To get user role in provided document.

*   **Signature**: `getUserRole$()`
*   **Params**: none
*   **Returns**: `Observable<string | null>`

## isPlanExpired\$()

To check if plan is expired or not.

*   **Signature**: `isPlanExpired$()`
*   **Params**: none
*   **Returns**: `Observable<boolean>`

## inviteUsers()

To invite a list of users to the document.

*   **Signature**: `inviteUsers(documentUsers: Array<DocumentUser>)`
*   **Params**: `documentUsers: Array<DocumentUser>`
*   **Returns**: none

## removeVeltContent()

To remove Velt specific content from provided html content.

*   **Signature**: `removeVeltContent(htmlContent: string)`
*   **Params**: `htmlContent: string`
*   **Returns**: `string`

## injectCustomCss()

To inject custom CSS.

*   **Signature**: `injectCustomCss(customCss: CustomCss)`
*   **Params**: `customCss: CustomCss`
*   **Returns**: none

## setLanguage()

To set the language.

*   **Signature**: `setLanguage(language: string)`
*   **Params**: `language: string`
*   **Returns**: none

## setTranslations()

To set the translations for the language.

*   **Signature**: `setTranslations(language: string, translations: { [key: string]: string })`
*   **Params**: `language: string, translations: { [key: string]: string }`
*   **Returns**: none

## enableAutoTranslation()

To enable auto translation.

*   **Signature**: `enableAutoTranslation()`
*   **Params**: none
*   **Returns**: none

## disableAutoTranslation()

To disable auto translation.

*   **Signature**: `disableAutoTranslation()`
*   **Params**: none
*   **Returns**: none

## getVeltInitState()

Subscribe to detect whether Velt is initialized.

*   **Signature**: `getVeltInitState()`
*   **Params**: none
*   **Returns**: `Observable<boolean>`


# React Hooks



## useIdentify()

Hook that calls [client.identify()](/get-started/setup/authenticate)

```jsx
import { useIdentify } from "@veltdev/react";
import { useEffect, useState } from "react";

export default function YourAuthComponent() {
  
  // Create the Velt user object
  let veltUser = {
    userId: "your-user-id",
    name: "John Smith"
    email: "jsmith@velt.dev",
    photoUrl: "https://i.pravatar.cc/304",
    organizationId: "theoffice",
  };
  

  //identify Velt user
  useIdentify(veltUser)


  return (
    <div>Your Auth Template</div>
  )
}

```

## useSetDocumentId()

Hook that calls [client.setDocumentId()](/get-started/setup/initialize-document)

```jsx
import { useSetDocumentId } from '@veltdev/react';

export default function YourDocument() {

  useSetDocumentId("my-document-id")

  return (
    <div>
        Your Document Template
    </div>
  )
}
```

## useUnsetDocumentId()

Hook that calls [client.unsetDocumentId()](https://docs.velt.dev/api-reference/api-methods/velt-client)

```jsx
import { useUnsetDocumentId } from '@veltdev/react';

export default function YourDocument() {

  useUnsetDocumentId()

  return (
    <div>
        Your Document Template
    </div>
  )
}
```

## useSetLocation()

Hook that calls [client.setLocation()](/key-concepts/locations/set-location)

<Warning>Hooks currently do not support automatic change detection in variables.</Warning>

```jsx
import { useSetLocation } from '@veltdev/react';

export default function YourDocument() {

  const handleSetLocation = () => {
    useSetLocation({
        scene: "scene1"
    })
  }


  return (
    <div>
        <button onClick={handleSetLocation}>Set Location to Scene 1</button>
    </div>
  )
}
```

## useLiveStateSyncUtils()

Hook that calls [client.getLiveStateSyncElement()](/realtime-collaboration/single-editor-mode/setup)

```jsx
import { useLiveStateSyncUtils } from '@veltdev/react';

export default function YourDocument() {

  let liveStateSyncElement = useLiveStateSyncUtils()
  //Enable Single Editor Mode
  liveStateSyncElement?.enableSingleEditorMode();


  return (
    <div>
        <input/>
    </div>
  )
}
```

## useLiveStateData()

Hook that calls [liveStateSyncElement.getLiveStateData()](/realtime-collaboration/live-state-sync/setup)

```jsx
import { useLiveStateData, useSetLiveStateData} from '@veltdev/react';

export default function YourDocument() {

  //sets the live state data object
  useSetLiveStateData("myUniqueId", { 
    "myKey": "hello world!",
  })

  let data = useLiveStateData("myUniqueId")

  return (
    <div>
        {data?.myKey}
    </div>
  )
}
```

## useSetLiveStateData()

Hook that calls [liveStateSyncElement.setLiveStateData()](/realtime-collaboration/live-state-sync/setup)

```jsx
import { useLiveStateData, useSetLiveStateData} from '@veltdev/react';

export default function YourDocument() {

  useSetLiveStateData("myUniqueId", {
    "myKey": "hello world!",
  })


  //gets the live state data object
  let data = useLiveStateData("myUniqueId")

  return (
    <div>
        {data?.myKey}
    </div>
  )
}
```

## useEditor()

The `useEditor()` hook is used to call [liveStateSyncElement.getEditor()](/realtime-collaboration/single-editor-mode/setup) without having to handle the subscription.

```jsx
import { useEditor} from '@veltdev/react';

export default function YourDocument() {

  let user = useEditor()
  console.log("Editor User Data: ", user)

  return (
    <div>
        Editor Email: {user.email}
        Editor Name: {user.name}
        Editor ID: {user.userId}
    </div>
  )
}
```

## useUserEditorState()

Hook that calls [liveStateSyncElement.isUserEditor()](/realtime-collaboration/single-editor-mode/setup)

```jsx
import { useUserEditorState} from '@veltdev/react';

export default function YourDocument() {

  let isEditor = useUserEditorState()
  console.log("Is User Editor?: ", isEditor)

  return (
    <div>
        Is User Editor?: {isEditor}
    </div>
  )
}
```

## useEditorAccessTimer()

With the `useEditorAccessTimer` hook, you can get the Editor Access Timer state.

```jsx
import { useEditorAccessTimer } from '@veltdev/react';

function YourReactComponent {

    const editorAccessTimer = useEditorAccessTimer();

    useEffect(() => {
        if (editorAccessTimer?.state === 'completed') {
            onEditorAccessTimerCompleted();
        }
    }, [editorAccessTimer]);

    const onEditorAccessTimerCompleted = () => {
        // If user is editor, make requester as editor
        acceptEditorAccessRequest();
        // If user is requester, make it as editor
        setUserAsEditor();
    }
}
```

The `editorAccessTimer` class has the following schema:

*   `state`: `'idle'` | `'inProgress'` | `'completed' `
*   `durationLeft`: `number`

## useEditorAccessRequestHandler()

Hook that calls [liveStateSyncElement.isEditorAccessRequested()](/realtime-collaboration/single-editor-mode/setup)

```jsx
import { useEditorAccessRequestHandler } from '@veltdev/react';

export default function YourDocument= () {
	const editorAccessRequested = useEditorAccessRequestHandler();


  return (
    <div>
        Is Editor Access Being Requested? : {editorAccessRequested}
    </div>
  )
}
```

## usePresenceUtils()

Hook that calls `client.getPresenceElement()`

```jsx
import { usePresenceUtils } from '@veltdev/react';

export default function YourDocument() {

  let presenceElement = usePresenceUtils();

  return (
    <div>
       
    </div>
  )
}
```

## useCursorUtils()

Hook that calls `client.getCursorElement()`

```jsx
import { useCursorUtils } from '@veltdev/react';

export default function YourDocument() {

  let cursorElement = useCursorUtils();

  return (
    <div>
       
    </div>
  )
}
```

## useCommentUtils()

Hook that calls `client.getCommentElement()`.

```jsx
import { useCommentUtils } from '@veltdev/react';

export default function YourDocument() {

  let commentElement = useCommentUtils();

  return (
    <div>
       
    </div>
  )
}
```

## useLiveSelectionUtils()

Hook that calls `client.getLiveSelectElement()`.

```jsx
import { useLiveSelectionUtils } from '@veltdev/react';

export default function YourDocument() {

  let liveSelectionElement = useLiveSelectionUtils()

  return (
    <div>
        <input/>
    </div>
  )
}
```

## useRecorderUtils()

Hook that calls `client.getRecorderElement()`.

```jsx
import { useRecorderUtils } from '@veltdev/react';

export default function YourDocument() {

  let recorderElement = useRecorderUtils();

  return (
    <div>
       
    </div>
  )
}
```

## useContactUtils()

Hook that calls `client.getContactElement()`.

```jsx
import { useContactUtils } from '@veltdev/react';

export default function YourDocument() {

  let contactElement = useContactUtils();

  return (
    <div>
       
    </div>
  )
}
```

## useContactSelected()

Hook that calls `client.onContactSelected()`.

```jsx
import React, { useEffect } from 'react';
import { useContactUtils, useContactSelected } from '@veltdev/react';

function YourComponent() {

  const contactUtils = useContactUtils();

  useEffect(() => {
    console.log('contactUtils: ', contactUtils);
  }, [contactUtils]);

  const onContactSelected = useContactSelected();

  useEffect(() => {
    console.log('onContactSelected: ', onContactSelected);
  }, [onContactSelected]);

  return (
    // Your component code
  );

}
```

## useAIRewriterUtils()

Hook that calls `client.getRewriterElement()`.

```jsx
import { useAIRewriterUtils } from '@veltdev/react';

export default function YourDocument() {

  let AIRewriterElement = useAIRewriterUtils();

  return (
    <div>
       
    </div>
  )
}
```

## useHuddleUtils()

Hook that calls `client.getHuddleElement()`.

```jsx
import { useHuddleUtils } from '@veltdev/react';

export default function YourDocument() {

  let huddleElement = useHuddleUtils();

  return (
    <div>
       
    </div>
  )
}
```

## useCommentAnnotations()

Hook that calls `commentElement.getAllCommentAnnotations()`

See [CommentAnnotations Class Model](/api-reference/models/CommentAnnotation)

```jsx
import { useCommentAnnotations } from '@veltdev/react';

export default function YourDocument() {

  let commentAnnotations = useCommentAnnotations('my-document-id', { id:'my-location-id',locationName:"MyLocationName"})


  return (
    <div>
       {commentAnnotations.map(x => <div>{x.annotationId}</div>)}
    </div>
  )
}
```

## useCommentModeState()

Hook that calls [commentElement.onCommentModeChange()](/async-collaboration/comments/customize-behavior/event-handlers)

```jsx
import { useCommentModeState } from '@veltdev/react';

export default function YourDocument() {

  let commentModeState = useCommentModeState()

  return (
    <div>
       Comment Mode is turned on: {commentModeState}
    </div>
  )
}
```

## useCommentAddHandler()

Hook that calls [commentElement.onCommentAdd()](/async-collaboration/comments/customize-behavior/event-handlers)

```jsx
import { useCommentAddHandler} from '@veltdev/react';

export default function YourDocument() {

  const commentAddEvent = useCommentAddHandler();
  useEffect(() => {
    console.log('commentAddEvent', commentAddEvent);
  }, [commentAddEvent]);


  return (
    <div>
       
    </div>
  )
}
```

## useCommentUpdateHandler()

Hook that calls [commentElement.onCommentUpdate()](/async-collaboration/comments/customize-behavior/event-handlers)

```jsx
import { useCommentUpdateHandler} from '@veltdev/react';

export default function YourDocument() {

  const commentUpdateEvent = useCommentUpdateHandler();
  useEffect(() => {
    console.log('commentUpdateEvent', commentUpdateEvent);
  }, [commentUpdateEvent]);

  return (
    <div>
       
    </div>
  )
}
```

## useCommentDialogSidebarClickHandler()

Hook that calls [commentElement.onSidebarButtonOnCommentDialogClick()](/async-collaboration/comments/customize-behavior/general-controls)

```jsx
import { useCommentDialogSidebarClickHandler} from '@veltdev/react';

export default function YourDocument() {

  const commentDialogSidebarClickEvent = useCommentDialogSidebarClickHandler();
  useEffect(() => {
    console.log('CommentDialog Sidebar button clicked');
  }, [commentDialogSidebarClickEvent]);

  return (
    <div>
       
    </div>
  )
}
```

## useCursorUsers()

Hook that calls `cursorElement.getOnlineUsersOnCurrentDocument()`

```jsx
import { useCursorUsers} from '@veltdev/react';

export default function YourDocument() {

  let cursorUsers = useCursorUsers()

  return (
    <div>
       Users: {cursorUsers.length} 
    </div>
  )
}
```

## usePresenceUsers()

Hook that calls `presenceElement.getOnlineUsersOnCurrentDocument()`

```jsx
import { usePresenceUsers} from '@veltdev/react';

export default function YourDocument() {

  let presenceUsers = usePresenceUsers()

  return (
    <div>
       Users: {presenceUsers.length} 
    </div>
  )
}
```

## useRecorderAddHandler()

Hook that calls `recorderElement.onRecordedData()`

```jsx
import { useRecorderAddHandler} from '@veltdev/react';

export default function YourDocument() {

  const recorderAddEvent = useRecorderAddHandler();

  useEffect(() => {
    console.log('recorderAddEvent', recorderAddEvent);
  }, [recorderAddEvent]);

  return (
    <div>
       
    </div>
  )
}
```

## useCommentSelectionChange

Hook that calls [commentElement.onCommentSelectionChange](/async-collaboration/comments/customize-behavior/event-handlers)

```jsx
import React, { useEffect } from 'react';
import { useCommentSelectionChangeHandler } from '@veltdev/react';

function YourComponent() {
    const commentSelectionChangeEvent = useCommentSelectionChangeHandler();

    useEffect(() => {
        console.log('commentSelectionChangeEvent', commentSelectionChangeEvent);
    }, [commentSelectionChangeEvent]);

    return (
        <>
            Selected Comment: {commentSelectionChange.annotation.id}
        </>
    );
}

```

## useVeltInitState

Hook that calls [client.getVeltInitState()](/api-reference/api-methods/velt-client)

```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]);
}
```

## useUnreadCommentCountByAnnotationId

```jsx
import { useUnreadCommentCountByAnnotationId } from '@veltdev/react';

export default function YourDocument() {

  let unreadCommentCountByAnnotationId = useUnreadCommentCountByAnnotationId(annotationId);

  return (
    <div>
       Unread Comment Count By Annotation Id: {unreadCommentCountByAnnotationId}
    </div>
  )
}
```

## useUnreadCommentAnnotationCountOnCurrentDocument

```jsx
import { useUnreadCommentAnnotationCountOnCurrentDocument } from '@veltdev/react';

export default function YourDocument() {

  let unreadCommentAnnotationCountOnCurrentDocument = useUnreadCommentAnnotationCountOnCurrentDocument();

  return (
    <div>
      Unread Comment Annotations: {unreadCommentAnnotationCountOnCurrentDocument}
    </div>
  )
}
```

## useUnreadCommentCountOnCurrentDocument

```jsx
import { useUnreadCommentCountOnCurrentDocument } from '@veltdev/react';

export default function YourDocument() {

  let unreadCommentCountOnCurrentDocument = useUnreadCommentCountOnCurrentDocument();

  return (
    <div>
       Unread Commment Count on Current Document: {unreadCommentCountOnCurrentDocument}
    </div>
  )
}
```

## useUnreadCommentAnnotationCountByLocationId

```jsx
import { useUnreadCommentAnnotationCountByLocationId } from '@veltdev/react';

export default function YourDocument() {

  let unreadCommentAnnotationCountByLocationId = useUnreadCommentAnnotationCountByLocationId(locationId);

  return (
    <div>
       Unread Comment Annotations By Location: {unreadCommentAnnotationCountByLocationId}
    </div>
  )
}
```

## useUnreadCommentCountByLocationId

```jsx
import { useUnreadCommentCountByLocationId } from '@veltdev/react';

export default function YourDocument() {

  let unreadCommentCountByLocationId = useUnreadCommentCountByLocationId(locationId);

  return (
    <div>
       Unread Comments By Location: {unreadCommentCountByLocationId}
    </div>
  )
}
```


# null



## AutocompleteItem Class

| Property    | Type   | Optional | Description                |
| ----------- | ------ | -------- | -------------------------- |
| id          | string | No       | Unique identifier          |
| name        | string | No       | Name of the item           |
| description | string | Yes      | Optional description       |
| icon        | object | Yes      | Optional icon information  |
| icon.url    | string | Yes      | URL of the icon            |
| icon.svg    | string | Yes      | SVG representation of icon |
| link        | string | Yes      | Link associated with item  |


# null



## `Comment` Class

| Property                | Type                                                                                        | Optional | Description                                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `commentId`             | number                                                                                      | No       | Unique identifier for the comment pin annotation. Auto generated.                                                                   |
| `type`                  | 'text' \| 'voice'                                                                           | No       | This determines the comment content type. Default is 'text'.                                                                        |
| `commentText`           | string                                                                                      | No       | The actual text content of the comment.                                                                                             |
| `commentHtml`           | string                                                                                      | Yes      | Same comment text but formatted in HTML.                                                                                            |
| `replaceContentHtml`    | string                                                                                      | Yes      | HTML content to replace the comment text when user accepts the comment.                                                             |
| `replaceContentText`    | string                                                                                      | Yes      | Text content to replace the comment text when user accepts the comment.                                                             |
| `commentVoiceUrl`       | string                                                                                      | Yes      | URL of the voice recording for the comment, if available.                                                                           |
| `from`                  | User                                                                                        | No       | The user who created this comment.                                                                                                  |
| `to`                    | User\[]                                                                                     | Yes      | List of users that were @mentioned in this comment.                                                                                 |
| `lastUpdated`           | Date                                                                                        | Yes      | Timestamp of when this comment was last updated. Auto generated.                                                                    |
| `editedAt`              | any                                                                                         | Yes      | Timestamp of when this comment was edited. Auto generated.                                                                          |
| `createdAt`             | any                                                                                         | Yes      | Timestamp of when this comment was created. Auto generated.                                                                         |
| `isEdited`              | boolean                                                                                     | Yes      | Whether the comment has been edited. Auto generated.                                                                                |
| `status`                | 'added' \| 'updated'                                                                        | No       | Status of the comment indicating whether it was newly added or updated.                                                             |
| `attachments`           | [Attachment](#attachment-class-properties)\[]                                               | No       | List of attachments associated with the comment.                                                                                    |
| `recorders`             | [RecordedData](/api-reference/models/Recorder#recordeddata-class-properties)\[]             | No       | List of recorded data associated with the comment.                                                                                  |
| `reactionAnnotationIds` | string\[]                                                                                   | No       | List of annotation IDs for reactions to the comment.                                                                                |
| `taggedUserContacts`    | [AutocompleteUserContactReplaceData](#autocompleteusercontactreplacedataclassproperties)\[] | No       | List of users that were @mentioned in this comment. This contains addition metadata that is used to display the @mention in the UI. |
| `customList`            | [AutocompleteReplaceData](#autocompletereplacedataclassproperties)\[]                       | No       | List of custom list items added to the comment.                                                                                     |
| `isDraft`               | boolean                                                                                     | No       | Whether the comment is in draft state.                                                                                              |

## `AutocompleteUserContactReplaceData` Class

| Property  | Type   | Optional | Description                                                        |
| --------- | ------ | -------- | ------------------------------------------------------------------ |
| `text`    | string | No       | The text displayed in the comment that represents the tagged user. |
| `userId`  | string | No       | The user ID of the tagged user.                                    |
| `contact` | User   | Yes      | The user object of the tagged user.                                |

## `AutocompleteReplaceData` Class

| Property | Type             | Optional | Description                                                        |
| -------- | ---------------- | -------- | ------------------------------------------------------------------ |
| `text`   | string           | No       | The text displayed in the comment that represents the custom item. |
| `custom` | AutocompleteItem | No       | The custom item object associated with this text.                  |

## `AutocompleteItem` Class Properties

| Property      | Type                             | Optional | Description                                                             |
| ------------- | -------------------------------- | -------- | ----------------------------------------------------------------------- |
| `id`          | string                           | No       | Unique identifier for the autocomplete item.                            |
| `name`        | string                           | No       | Name or label of the autocomplete item.                                 |
| `description` | string                           | Yes      | Additional description of the autocomplete item.                        |
| `icon`        | `{ url?: string, svg?: string }` | Yes      | Icon associated with the autocomplete item. Can be a URL or SVG string. |
| `link`        | string                           | Yes      | Optional link associated with the autocomplete item.                    |

## `AutocompleteData` Class

| Property      | Type                             | Optional | Description                                                                   |
| ------------- | -------------------------------- | -------- | ----------------------------------------------------------------------------- |
| `hotkey`      | string                           | No       | The hotkey or trigger for this autocomplete data.                             |
| `description` | string                           | Yes      | Optional description of the autocomplete data.                                |
| `type`        | 'custom' \| 'contact' \| 'group' | No       | The type of autocomplete data. Default is 'custom'.                           |
| `data`        | AutocompleteItem\[]              | No       | An array of AutocompleteItem objects containing the actual autocomplete data. |

## `Attachment` Class

| Property                   | Type   | Optional | Description                                           |
| -------------------------- | ------ | -------- | ----------------------------------------------------- |
| `attachmentId`             | number | No       | Unique identifier for the attachment. Auto-generated. |
| `name`                     | string | Yes      | File name of the attachment.                          |
| `size`                     | number | Yes      | File size of the attachment.                          |
| `type`                     | string | Yes      | File type of the attachment.                          |
| `url`                      | string | Yes      | Download URL of the attachment.                       |
| `thumbnail`                | string | Yes      | Thumbnail image in base64 format.                     |
| `thumbnailWithPlayIconUrl` | string | Yes      | URL of the thumbnail with a play icon overlay.        |
| `metadata`                 | any    | Yes      | Additional metadata of the attachment.                |
| `mimeType`                 | any    | Yes      | MIME type of the attachment.                          |


# CommentAnnotation



## `CommentAnnotation` Class

| Property                  | Type                                                                                       | Optional | Description                                                                                                         |
| ------------------------- | ------------------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `annotationId`            | string                                                                                     | No       | Unique identifier for the comment pin annotation. Auto generated.                                                   |
| `comments`                | [Comment](/api-reference/models/Comment)\[]                                                | No       | The list of all comments part of this annotation.                                                                   |
| `commentCategories`       | [CustomCategory](#customcategory-interface-properties)\[]                                  | No       | The list of categories that this comment pin annotation belongs to.                                                 |
| `from`                    | User                                                                                       | No       | The user who created this comment pin annotation.                                                                   |
| `color`                   | string                                                                                     | Yes      | Color used for the comment pin annotation.                                                                          |
| `resolved`                | boolean                                                                                    | Yes      | Whether the comment annotation is marked resolved. Deprecated.                                                      |
| `inProgress`              | boolean                                                                                    | Yes      | Whether the comment annotation is marked as in progress. Deprecated.                                                |
| `lastUpdated`             | any                                                                                        | Yes      | Timestamp when the comment annotation was last updated. Auto generated.                                             |
| `createdAt`               | any                                                                                        | Yes      | Timestamp when the comment annotation was created. Auto generated.                                                  |
| `position`                | CursorPosition \| null                                                                     | Yes      | Cursor position relative to the comment annotation.                                                                 |
| `locationId`              | number \| null                                                                             | Yes      | Unique location id generated from provided location.                                                                |
| `location`                | Location \| null                                                                           | Yes      | Set location to identify user on sub document.                                                                      |
| `type`                    | string                                                                                     | Yes      | Type of the comment annotation.                                                                                     |
| `selectAllContent`        | boolean                                                                                    | Yes      | If true, sets text comment annotation on all the text content.                                                      |
| `approved`                | boolean                                                                                    | Yes      | Whether the comment annotation is approved.                                                                         |
| `status`                  | [CustomStatus](#customstatus-interface-properties)                                         | No       | Status of the comment annotation. Default: [CommentAnnotationStatusMap.OPEN](#default-status-object)                |
| `annotationIndex`         | number                                                                                     | Yes      | Index of current annotation in the list.                                                                            |
| `pageInfo`                | [PageInfo](/api-reference/models/PageInfo)                                                 | Yes      | Page information related to the comment annotation.                                                                 |
| `assignedTo`              | User                                                                                       | Yes      | User to whom the comment annotation is assigned.                                                                    |
| `priority`                | [CustomPriority](#custompriority-interface-properties)                                     | Yes      | Priority level of the comment annotation.                                                                           |
| `ghostComment`            | GhostComment \| null                                                                       | Yes      | Placeholder for a non-existing comment.                                                                             |
| `context`                 | any                                                                                        | Yes      | Custom context data provided by the user.                                                                           |
| `resolvedByUserId`        | string                                                                                     | Yes      | ID of the user who resolved the comment.                                                                            |
| `subscribedUsers`         | [CommentAnnotationSubscribedUsers](#commentannotationsubscribedusers-class-properties)     | Yes      | Users who explicitly subscribe to the comment.                                                                      |
| `unsubscribedUsers`       | [CommentAnnotationUnsubscribedUsers](#commentannotationunsubscribedusers-class-properties) | Yes      | Users who explicitly unsubscribe to the comment.                                                                    |
| `multiThreadAnnotationId` | string                                                                                     | Yes      | This is the ID of the multithread annotation group it belongs to, if this was created when multithread mode was on. |
| `isDraft`                 | boolean                                                                                    | Yes      | Indicates if the comment annotation is in draft state.                                                              |
| `customList`              | [CustomAnnotationDropdownItem](#customannotationdropdownitem)\[]                           | Yes      | Custom list of items for the comment annotation.                                                                    |

## `CommentAnnotationSubscribedUsers` Class

| Property     | Type     | Optional | Description                             |                                                                                                                                                                                |
| ------------ | -------- | -------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `userIdHash` | string   | No       | The user ID of the subscribed user.     |                                                                                                                                                                                |
| `user`       | User     | No       | The user object of the subscribed user. |                                                                                                                                                                                |
| `type`       | 'manual' | 'auto'   | No                                      | Manual: if the user used the UI option to subscribe; Auto: When the system automatically adds the user to the subscribed list. eg: when the user creates a comment annotation. |

## `CommentAnnotationUnsubscribedUsers` Class

| Property     | Type     | Optional | Description                               |                                                                                                                                                                                                |
| ------------ | -------- | -------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `userIdHash` | string   | No       | The user ID of the unsubscribed user.     |                                                                                                                                                                                                |
| `user`       | User     | No       | The user object of the unsubscribed user. |                                                                                                                                                                                                |
| `type`       | 'manual' | 'auto'   | No                                        | Manual: if the user used the UI option to unsubscribe; Auto: When the system automatically removes the user from the unsubscribed list. eg: when the comment where user was tagged is deleted. |

## `CustomFilter` Class

| Property | Type   | Optional | Description                              |
| -------- | ------ | -------- | ---------------------------------------- |
| `id`     | string | No       | Unique identifier for the custom filter. |
| `color`  | string | No       | Color associated with the custom filter. |
| `name`   | string | No       | Name or label of the custom filter.      |

## `CustomPriority` Class

| Property     | Type   | Optional | Description                                  |
| ------------ | ------ | -------- | -------------------------------------------- |
| `id`         | string | No       | Unique identifier for the custom priority.   |
| `color`      | string | No       | Color associated with the custom priority.   |
| `name`       | string | No       | Name or label of the custom priority.        |
| `lightColor` | string | Yes      | Light color variant for the custom priority. |

## `CustomStatus` Class

| Property     | Type       | Optional | Description                                               |
| ------------ | ---------- | -------- | --------------------------------------------------------- |
| `id`         | string     | No       | Unique identifier for the custom status.                  |
| `color`      | string     | No       | Color associated with the custom status.                  |
| `name`       | string     | No       | Name or label of the custom status.                       |
| `type`       | StatusType | No       | Type of the status (`default`, `ongoing`, or `terminal`). |
| `lightColor` | string     | Yes      | Light color for the custom status.                        |
| `svg`        | string     | Yes      | Raw SVG string for the custom status.                     |
| `iconUrl`    | string     | Yes      | URL to an icon image for the custom status.               |

## `CustomCategory` Class

| Property | Type   | Optional | Description                                |
| -------- | ------ | -------- | ------------------------------------------ |
| `id`     | string | No       | Unique identifier for the custom category. |
| `color`  | string | No       | Color associated with the custom category. |
| `name`   | string | No       | Name or label of the custom category.      |

## CustomAnnotationDropdownData

Represents the configuration for a custom annotation dropdown.

| Property    | Type                                                             | Description                                                  |
| ----------- | ---------------------------------------------------------------- | ------------------------------------------------------------ |
| type        | `multi` \| `single`                                              | The type of the custom annotation dropdown.                  |
| placeholder | string                                                           | The placeholder text for the dropdown. Defaults to 'Select'. |
| data        | [CustomAnnotationDropdownItem](#customannotationdropdownitem)\[] | An array of dropdown items.                                  |

## CustomAnnotationDropdownItem

Represents an item in a custom annotation dropdown.

| Property | Type   | Description                                  |
| -------- | ------ | -------------------------------------------- |
| id       | string | The unique identifier for the dropdown item. |
| label    | string | The display text for the dropdown item.      |

## Default Status Object

The default status object is defined in the `CommentAnnotationStatusMap` constant. It includes three predefined statuses: OPEN, IN\_PROGRESS, and RESOLVED. Each status is an object with the following structure:

```js
{
  OPEN: {
    id: 'OPEN',
    name: 'Open',
    color: '#625DF5',
    lightColor: '#E7E8FA',
    type: 'default',
    svg: `
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        fill-rule="evenodd"
        clip-rule="evenodd"
        d="M8.00016 13.3333C10.9457 13.3333 13.3335 10.9455 13.3335 8.00001C13.3335 5.05449 10.9457 2.66668 8.00016 2.66668C5.05464 2.66668 2.66683 5.05449 2.66683 8.00001C2.66683 10.9455 5.05464 13.3333 8.00016 13.3333ZM8.00016 14.6667C11.6821 14.6667 14.6668 11.6819 14.6668 8.00001C14.6668 4.31811 11.6821 1.33334 8.00016 1.33334C4.31826 1.33334 1.3335 4.31811 1.3335 8.00001C1.3335 11.6819 4.31826 14.6667 8.00016 14.6667Z"
        fill="currentColor"
      />
    </svg>
    `
  },
  IN_PROGRESS: {
    id: 'IN_PROGRESS',
    name: 'In Progress',
    color: '#ECB000',
    lightColor: '#FEFCEA',
    type: 'ongoing',
    svg: `
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        fill-rule="evenodd"
        clip-rule="evenodd"
        d="M8.00016 13.3333C10.9457 13.3333 13.3335 10.9455 13.3335 8.00001C13.3335 5.05449 10.9457 2.66668 8.00016 2.66668C5.05464 2.66668 2.66683 5.05449 2.66683 8.00001C2.66683 10.9455 5.05464 13.3333 8.00016 13.3333ZM8.00016 14.6667C11.6821 14.6667 14.6668 11.6819 14.6668 8.00001C14.6668 4.31811 11.6821 1.33334 8.00016 1.33334C4.31826 1.33334 1.3335 4.31811 1.3335 8.00001C1.3335 11.6819 4.31826 14.6667 8.00016 14.6667Z"
        fill="currentColor"
      />
      <path
        fill-rule="evenodd"
        clip-rule="evenodd"
        d="M8.00016 4C8.36835 4 8.66683 4.29848 8.66683 4.66667V7.72386L10.1382 9.19526C10.3986 9.45561 10.3986 9.87772 10.1382 10.1381C9.87788 10.3984 9.45577 10.3984 9.19542 10.1381L7.52876 8.4714C7.40373 8.34638 7.3335 8.17681 7.3335 8V4.66667C7.3335 4.29848 7.63197 4 8.00016 4Z"
        fill="currentColor"
      />
    </svg>
    `
  },
  RESOLVED: {
    id: 'RESOLVED',
    name: 'Resolved',
    color: '#00C48C',
    lightColor: '#E7FAF2',
    type: 'terminal',
    svg: `
    <svg
      width="17"
      height="16"
      viewBox="0 0 17 16"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path
        fill-rule="evenodd"
        clip-rule="evenodd"
        d="M8.50016 13.3333C11.4457 13.3333 13.8335 10.9455 13.8335 8.00001C13.8335 5.05449 11.4457 2.66668 8.50016 2.66668C5.55464 2.66668 3.16683 5.05449 3.16683 8.00001C3.16683 10.9455 5.55464 13.3333 8.50016 13.3333ZM8.50016 14.6667C12.1821 14.6667 15.1668 11.6819 15.1668 8.00001C15.1668 4.31811 12.1821 1.33334 8.50016 1.33334C4.81826 1.33334 1.8335 4.31811 1.8335 8.00001C1.8335 11.6819 4.81826 14.6667 8.50016 14.6667Z"
        fill="currentColor"
      />
      <path
        d="M5.8335 8L7.8335 10L11.8335 6"
        class="checkmark"
        stroke="currentColor"
        stroke-width="1.2"
        stroke-miterlimit="10"
        stroke-linecap="round"
        stroke-linejoin="round"
      />
    </svg>
    `
  },
}
```


# CommentSelectionChangeData



## `CommentSelectionChangeData` Class

| Property     | Type              | Optional | Description                            |
| ------------ | ----------------- | -------- | -------------------------------------- |
| `selected`   | boolean           | Yes      | Whether a comment is selected          |
| `annotation` | CommentAnnotation | Yes      | Object data of the selected annotation |


# CommentSidebarConfig



## `FilterTypeConfig` Class

| Property         | Type    | Optional | Description                                             |
| ---------------- | ------- | -------- | ------------------------------------------------------- |
| `name`           | string  | Yes      | The name of the filter type.                            |
| `enable`         | boolean | Yes      | Enables or disables the filter type.                    |
| `multiSelection` | boolean | Yes      | Allows multiple selections if set to true.              |
| `enableGrouping` | boolean | Yes      | Enables grouping within the filter type if set to true. |

## `CommentSidebarFilterConfig` Class

| Property      | Type             | Optional | Description                                 |
| ------------- | ---------------- | -------- | ------------------------------------------- |
| `location`    | FilterTypeConfig | Yes      | Configuration for the location filter type. |
| `people`      | FilterTypeConfig | Yes      | Configuration for the people filter type.   |
| `priority`    | FilterTypeConfig | Yes      | Configuration for the priority filter type. |
| `category`    | FilterTypeConfig | Yes      | Configuration for the category filter type. |
| `commentType` | FilterTypeConfig | Yes      | Configuration for the comment type filter.  |
| `version`     | FilterTypeConfig | Yes      | Configuration for the version filter type.  |

## `CommentSidebarGroupConfig` Class

| Property | Type    | Optional | Description                   |
| -------- | ------- | -------- | ----------------------------- |
| `enable` | boolean | Yes      | Enables or disables grouping. |
| `name`   | string  | Yes      | The name of the group.        |

## `CommentSidebarFilters` Class

| Property   | Type        | Optional | Description                                                             |
| ---------- | ----------- | -------- | ----------------------------------------------------------------------- |
| `location` | Location\[] | Yes      | Array of `Location` objects for the location filters.                   |
| `people`   | Object\[]   | Yes      | Array of objects with `userId`, `email`, and `name` for people filters. |
| `priority` | string\[]   | Yes      | Array of priority filters.                                              |
| `status`   | string\[]   | Yes      | Array of status filters.                                                |
| `category` | string\[]   | Yes      | Array of category filters.                                              |
| `version`  | Object\[]   | Yes      | Array of objects with `id` and optional `name` for version filters.     |


# CommentSidebarCustomActionEventData



## `CommentSidebarCustomActionEventData` Class

| Property             | Type                                        | Optional | Description                                                                 |
| -------------------- | ------------------------------------------- | -------- | --------------------------------------------------------------------------- |
| `actions`            | CommentSidebarCustomActionsState            | No       | Map of custom action button IDs and their states                            |
| `data`               | CommentAnnotation\[]                        | No       | List of all unfiltered CommentAnnotations available in the comments sidebar |
| `unreadDataMap`      | `{ [commentAnnotationId: string]: number }` | No       | Map of comment annotation id and the number of unread comments it has       |
| `systemFilteredData` | CommentAnnotation\[]                        | No       | List of filtered CommentAnnotations based on system filters                 |

## `CommentSidebarCustomActionsState` Class

| Property        | Type    | Optional | Description                                          |
| --------------- | ------- | -------- | ---------------------------------------------------- |
| `[key: string]` | boolean | No       | Custom Action Button ID you defined in the wireframe |


# CommentSidebarData



## `CommentSidebarData` Class

| Property      | Type                 | Optional | Description                                     |
| ------------- | -------------------- | -------- | ----------------------------------------------- |
| `groupId`     | string               | Yes      | ID of the group. Defaults to 'others'           |
| `groupName`   | string               | Yes      | Name of the group. Defaults to 'Others'         |
| `isExpanded`  | boolean              | Yes      | Whether the group is expanded. Defaults to true |
| `annotations` | CommentAnnotation\[] | No       | List of CommentAnnotations in the group         |

## `Options` Class

| Property   | Type    | Optional | Description                                 |
| ---------- | ------- | -------- | ------------------------------------------- |
| `grouping` | boolean | Yes      | Whether to group the data. Defaults to true |


# Velt Client Config



## `Config` Class Properties

| Property                | Type           | Optional | Default      | Description                                                                                                              |
| ----------------------- | -------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------------ |
| `urlAllowList`          | string\[]      | Yes      | All pages    | Restricts Velt features to specific pages by specifying partial URL strings.                                             |
| `featureAllowList`      | FeatureType\[] | Yes      | All features | Only allows the provided Velt features to run.                                                                           |
| `userPlanAllowList`     | string\[]      | Yes      | All users    | Restricts Velt features to specific user plans.                                                                          |
| `userIdAllowList`       | string\[]      | Yes      | All users    | Restricts Velt features to specific users.                                                                               |
| `usePrefersColorScheme` | boolean        | Yes      | -            | If set to true, listens to changes on the `prefers-color-scheme` media query to set the global theme of Velt components. |


# ContactListScopeForOrganizationUsers



```jsx
export enum ContactListScopeForOrganizationUsers {
  ALL = 'all', // Show all the contacts
  ORGANIZATION = 'organization', // Show organization contacts.
  ORGANIZATION_USER_GROUP = 'organizationUserGroup', // Show organization user groups.
  DOCUMENT = 'document', // Show document contacts.
}
```


# CursorUser



## `CursorUser` Class Properties:

| Property       | Type                   | Optional | Description                                                                             |
| -------------- | ---------------------- | -------- | --------------------------------------------------------------------------------------- |
| `userId`       | string                 | No       | Unique user identifier that you use to identify your user.                              |
| `name`         | string                 | Yes      | Your user's full name. Default: Random avatar name.                                     |
| `email`        | string                 | Yes      | Your user's email address.                                                              |
| `photoUrl`     | string                 | Yes      | Your user's display picture URL. Default: Random avatar image.                          |
| `comment`      | string                 | Yes      | Short comment that user can add to their live cursor.                                   |
| `onlineStatus` | string                 | No       | User's online status (active, inactive, offline). Auto generated.                       |
| `color`        | string                 | Yes      | A random color assigned to the user for the session, used on avatar border/live cursor. |
| `timestamp`    | any                    | No       | Server Timestamp.                                                                       |
| `type`         | string                 | Yes      | User type.                                                                              |
| `locationId`   | number \| null         | Yes      | Unique location id from provided location.                                              |
| `location`     | Location \| null       | Yes      | Location to identify user on sub document.                                              |
| `position`     | CursorPosition \| null | Yes      | User’s cursor position on their screen.                                                 |
| `isReadOnly`   | boolean                | Yes      | Indicates if user is readonly.                                                          |
| `isAnonymous`  | boolean                | Yes      | Indicates if user is anonymous and can only view comments.                              |


# CustomCss



## `CustomCss` Class

| Property | Type               | Optional | Description                                                           |
| -------- | ------------------ | -------- | --------------------------------------------------------------------- |
| `type`   | 'link' \| 'styles' | No       | The type of custom CSS, either a link to a CSS file or inline styles. |
| `value`  | string             | No       | The value of the custom CSS, either a URL or CSS styles.              |


# CustomFilter



## `CustomFilter` Interface Properties

| Property | Type   | Optional | Description                              |
| -------- | ------ | -------- | ---------------------------------------- |
| `id`     | string | No       | Unique identifier for the custom filter. |
| `color`  | string | No       | Color associated with the custom filter. |
| `name`   | string | No       | Name or label of the custom filter.      |

## `CustomPriority` Interface Properties

| Property     | Type   | Optional | Description                                  |
| ------------ | ------ | -------- | -------------------------------------------- |
| `id`         | string | No       | Unique identifier for the custom priority.   |
| `color`      | string | No       | Color associated with the custom priority.   |
| `name`       | string | No       | Name or label of the custom priority.        |
| `lightColor` | string | Yes      | Light color variant for the custom priority. |

## `CustomStatus` Interface Properties

| Property     | Type       | Optional | Description                                               |
| ------------ | ---------- | -------- | --------------------------------------------------------- |
| `id`         | string     | No       | Unique identifier for the custom status.                  |
| `color`      | string     | No       | Color associated with the custom status.                  |
| `name`       | string     | No       | Name or label of the custom status.                       |
| `type`       | StatusType | No       | Type of the status (`default`, `ongoing`, or `terminal`). |
| `lightColor` | string     | Yes      | Light color for the custom status.                        |
| `svg`        | string     | Yes      | Raw SVG string for the custom status.                     |
| `iconUrl`    | string     | Yes      | URL to an icon image for the custom status.               |

## `CustomCategory` Interface Properties

| Property | Type   | Optional | Description                                |
| -------- | ------ | -------- | ------------------------------------------ |
| `id`     | string | No       | Unique identifier for the custom category. |
| `color`  | string | No       | Color associated with the custom category. |
| `name`   | string | No       | Name or label of the custom category.      |


# DocumentMetadata



## `DocumentMetadata` Class Properties

| Property           | Type                                       | Description                                      |
| ------------------ | ------------------------------------------ | ------------------------------------------------ |
| `clientDocumentId` | string                                     | The document ID set by you.                      |
| `documentId`       | string                                     | The document ID set by the SDK.                  |
| `documentName`     | string                                     | Name of the document                             |
| `pageInfo`         | [PageInfo](/api-reference/models/PageInfo) | Additional information about the document's page |


# EditorAccessTimer



## `EditorAccessTimer` Class Properties

| Property       | Type                                    | Optional | Description                                                |
| -------------- | --------------------------------------- | -------- | ---------------------------------------------------------- |
| `state`        | `'idle' \| 'inProgress' \| 'completed'` | No       | The state of the Editor Access Request timer               |
| `durationLeft` | `number`                                | Yes      | Duration left for the editor access timer to be completed. |


# null



Feature Types Enum:

```jsx
export enum Features {
  AREA = 'area',
  ARROW = 'arrow',
  AUDIO_HUDDLE = 'audioHuddle',
  COMMENT = 'comment',
  CURSOR = 'cursor',
  HUDDLE = 'huddle',
  LIVE_STATE_SYNC = 'liveStateSync',
  PRESENCE = 'presence',
  TAG = 'tag',
  RECORDER = 'recorder',
  REWRITER = 'rewriter',
  LIVE_SELECTION = 'liveSelection',
}
```


# FlockOptions



## `FlockOptions` Class Properties

| Property                   | Type                    | Optional | Description                                                                                                                                                 |
| -------------------------- | ----------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `useHistoryAPI`            | boolean                 | No       | Indicates whether the application should use the HTML5 History API for navigation.                                                                          |
| `onNavigate`               | (url: PageInfo) => void | Yes      | A callback function that is called when navigation occurs. It takes a `PageInfo` object as its argument, which likely contains details about the new page.  |
| `disableDefaultNavigation` | boolean                 | No       | If `true`, the application's default navigation handling is disabled, perhaps to be managed manually or by another system.                                  |
| `darkMode`                 | boolean                 | No       | A flag indicating whether the application should display in dark mode, a display preference that may be more comfortable for users in low-light conditions. |


# LiveStateData



## `LiveStateData` Class

| Property          | Type                                | Optional | Description                                                                                              |
| ----------------- | ----------------------------------- | -------- | -------------------------------------------------------------------------------------------------------- |
| \`id              | string                              | No       | A unique identifier likely used for quick reference and indexing. It's an MD5 hash of `liveStateDataId`. |
| `liveStateDataId` | string                              | No       | A unique identifier for the state data being synced.                                                     |
| `data`            | string \| number \| boolean \| JSON | No       | The actual data you want to synchronize across clients.                                                  |
| `lastUpdated`     | any                                 | No       | A timestamp or similar data indicating the last time the state data was updated.                         |
| `updatedBy`       | `User`                              | No       | The user who last updated the state data.                                                                |
| `tabId`           | string \| null                      | Yes      | An identifier that could be used to associate the state data with a specific tab or instance.            |

## `SingleEditorLiveStateData` Class

| Property              | Type           | Optional | Description                                |
| --------------------- | -------------- | -------- | ------------------------------------------ |
| `editor`              | User \| null   | Yes      | The user who is currently editing, if any. |
| `requestEditorAccess` | Object \| null | Yes      | Details about a request for editor access. |
| `tabId`               | string \| null | Yes      | The identifier of the tab, if applicable.  |

## `requestEditorAccess` Class:

| Property              | Type                                                 | Optional | Description                                              |
| --------------------- | ---------------------------------------------------- | -------- | -------------------------------------------------------- |
| `user`                | User                                                 | No       | The user requesting editor access.                       |
| `requestedAt`         | any                                                  | No       | The timestamp when the access was requested.             |
| `status`              | 'pending' \| 'accepted' \| 'rejected' \| 'cancelled' | No       | The status of the access request.                        |
| `editorAccessTimeout` | number                                               | No       | Timeout duration for the editor access.                  |
| `tabId`               | string \| null                                       | Yes      | The identifier of the tab related to the access request. |

## `SingleEditorConfig` Class

| Property          | Type    | Optional | Description                                                                                   |
| ----------------- | ------- | -------- | --------------------------------------------------------------------------------------------- |
| `customMode`      | boolean | Yes      | Enables/disables custom mode. In custom mode, input elements are not disabled for the viewer. |
| `singleTabEditor` | boolean | No       | Enables/disables editor mode on a single tab only.                                            |

## `UserEditorAccess` Class

| Property               | Type    | Optional | Description                                                 |
| ---------------------- | ------- | -------- | ----------------------------------------------------------- |
| `isEditor`             | boolean | Yes      | Indicates whether the user has editor privileges.           |
| `isEditorOnCurrentTab` | boolean | Yes      | Indicates whether the user is an editor on the current tab. |


# null



## LiveStateDataMap Properties

| Property                        | Type                                            | Optional | Description                                                                             |
| ------------------------------- | ----------------------------------------------- | -------- | --------------------------------------------------------------------------------------- |
| `custom`                        | `{ [liveStateDataId: string]: LiveStateData; }` | Yes      | Map of all unique LiveStateData set by you on the given document.                       |
| `default`                       | Object                                          | Yes      | Map of all unique LiveStateData set by the default editor on the given document.        |
| `default.singleEditor`          | `SingleEditorLiveStateData`                     |          | Part of `default`, representing single editor live state data.                          |
| `default.autoSyncState`         | Object                                          |          | Part of `default`, representing auto synchronization state.                             |
| `default.autoSyncState.current` | `LiveStateData`                                 |          | Part of `autoSyncState`, current live state data.                                       |
| `default.autoSyncState.history` | `[liveStateDataId: string]: LiveStateData`      |          | Part of `autoSyncState`, map of historical live state data keyed by live state data ID. |


# null



## `Location` Class Properties

Here's the `Location` class information formatted as a Markdown table, including a column to indicate whether each field is optional and a note on the dynamic properties:

| Property        | Type    | Optional | Description                                       |
| --------------- | ------- | -------- | ------------------------------------------------- |
| `id`            | string  | No       | Unique identifier for the location.               |
| `locationName`  | string  | Yes      | Name of the location.                             |
| `version`       | Version | Yes      | Version information provided by the user.         |
| `[key: string]` | any     | Yes      | Additional dynamic properties as key-value pairs. |

## Version

Here's the `Version` class information formatted as a Markdown table, including a column to indicate whether each field is optional:

| Property | Type   | Optional | Description                        |
| -------- | ------ | -------- | ---------------------------------- |
| `id`     | string | No       | Unique identifier for the version. |
| `name`   | string | No       | Name of the version.               |


# LocationMetadata



## `LocationMetadata` Class Properties

| Property     | Type               | Optional | Description                                                   |
| ------------ | ------------------ | -------- | ------------------------------------------------------------- |
| `locationId` | number             | Yes      | Unique location id generated from client location information |
| `location`   | `Location` \| null | Yes      | Location object provided by a client                          |


# MediaPreviewConfig



## `MediaPreviewConfig` Class Properties

| Property         | Type        | Optional | Description                       |
| ---------------- | ----------- | -------- | --------------------------------- |
| `audio`          | Object      | Yes      | Configuration for audio preview   |
| `audio.enabled`  | boolean     | Yes      | Whether audio preview is enabled  |
| `audio.deviceId` | string      | Yes      | Device ID for audio input         |
| `video`          | Object      | Yes      | Configuration for video preview   |
| `video.enabled`  | boolean     | Yes      | Whether video preview is enabled  |
| `video.deviceId` | string      | Yes      | Device ID for video input         |
| `screen`         | Object      | Yes      | Configuration for screen preview  |
| `screen.enabled` | boolean     | Yes      | Whether screen preview is enabled |
| `screen.stream`  | MediaStream | Yes      | MediaStream for screen sharing    |


# null



## `Notification` Class Properties

| Property                             | Type                                | Optional | Description                                                                   |
| ------------------------------------ | ----------------------------------- | -------- | ----------------------------------------------------------------------------- |
| `id`                                 | `string`                            | No       | Notification ID                                                               |
| `notificationSource`                 | `string`                            | No       | Notification source. e.g., 'comment', 'custom', etc.                          |
| `actionType`                         | `string`                            | Yes      | Action that triggered the notification. e.g., 'added'                         |
| `isUnread`                           | `boolean`                           | Yes      | Whether the notification is unread for the user                               |
| `actionUser`                         | `User`                              | Yes      | The user who triggered the action                                             |
| `timestamp`                          | `number`                            | Yes      | Timestamp of the notification                                                 |
| `displayHeadlineMessage`             | `string`                            | Yes      | The headline message of the notification                                      |
| `displayBodyMessage`                 | `string`                            | Yes      | The body message of the notification                                          |
| `displayHeadlineMessageTemplate`     | `string`                            | Yes      | The template of the headline message                                          |
| `displayHeadlineMessageTemplateData` | `object`                            | Yes      | The data used to fill the headline message template                           |
| `forYou`                             | `boolean`                           | Yes      | Whether the notification is for the current logged-in user                    |
| `targetAnnotationId`                 | `string`                            | Yes      | ID of the annotation that triggered the notification                          |
| `notificationSourceData`             | `any`                               | Yes      | The data of the notification source. e.g., `CommentAnnotation`                |
| `metadata`                           | `NotificationMetadata`              | Yes      | Metadata for the current notification. e.g., `documentId`                     |
| `notifyUsers`                        | `{ [emailHash: string]: boolean }`  | Yes      | Map of email hashes to boolean values indicating whether to notify the user   |
| `notifyUsersByUserId`                | `{ [userIdHash: string]: boolean }` | Yes      | Map of user ID hashes to boolean values indicating whether to notify the user |

## `displayHeadlineMessageTemplateData` Object Properties

| Property        | Type     | Description                             |
| --------------- | -------- | --------------------------------------- |
| `actionUser`    | `User`   | The user who performed the action       |
| `recipientUser` | `User`   | The user receiving the notification     |
| `actionMessage` | `string` | The message describing the action       |
| `project`       | `string` | The project related to the notification |
| `[key: string]` | `any`    | Any additional custom properties        |

## `NotificationMetadata` Properties

| Property               | Type       | Optional | Description                                        |
| ---------------------- | ---------- | -------- | -------------------------------------------------- |
| `apiKey`               | `string`   | Yes      | Your API key                                       |
| `clientOrganizationId` | `string`   | Yes      | The organization ID that you set                   |
| `organizationId`       | `string`   | Yes      | The organization ID generated by us                |
| `clientDocumentId`     | `string`   | Yes      | The document ID that you set                       |
| `documentId`           | `string`   | Yes      | The document ID generated by us                    |
| `locationId`           | `number`   | Yes      | The unique location ID                             |
| `location`             | `Location` | Yes      | The location object                                |
| `documentMetadata`     | Object     | Yes      | Contains the complete document metadata object     |
| `organizationMetadata` | Object     | Yes      | Contains the complete organization metadata object |


# PageInfo



## `PageInfo` Class Properties

| Property      | Type   | Optional | Description                            |
| ------------- | ------ | -------- | -------------------------------------- |
| `url`         | string | Yes      | URL of the webpage                     |
| `path`        | string | Yes      | Path of the webpage excluding base url |
| `baseUrl`     | string | Yes      | Base URL (domain) of a webpage         |
| `title`       | string | Yes      | Title of the webpage                   |
| `commentUrl`  | string | Yes      | Reference url of a comment annotation  |
| `recorderUrl` | string | Yes      | Reference url of a recorder annotation |
| `screenWidth` | number | Yes      | User's screen width. Auto generated.   |


# PresenceUser



## `PresenceUser` Class Properties

| Property           | Type             | Optional | Description                                                |
| ------------------ | ---------------- | -------- | ---------------------------------------------------------- |
| `userId`           | String           | No       | Unique user identifier                                     |
| `name`             | String           | Yes      | User's full name (Default: Random avatar name)             |
| `email`            | String           | Yes      | User's email address                                       |
| `photoUrl`         | String           | Yes      | User's display picture URL (Default: Random avatar image)  |
| `onlineStatus`     | String           | No       | Online status (active, inactive, offline) (Auto generated) |
| `color`            | String           | Yes      | Assigned color for the user (Auto generated)               |
| `timestamp`        | Any              | No       | Server Timestamp                                           |
| `type`             | String           | Yes      | User type                                                  |
| `selections`       | Any              | Yes      | User selections                                            |
| `documentParamsId` | Number, null     | Yes      | Deprecated unique document params ID                       |
| `documentParams`   | Object, null     | Yes      | Deprecated document params                                 |
| `locationId`       | Number, null     | Yes      | Unique location ID                                         |
| `location`         | `Location`, null | Yes      | Location of user on sub document                           |
| `isReadOnly`       | Boolean          | Yes      | Indicates if user is readonly                              |
| `isAnonymous`      | Boolean          | Yes      | If user can only view comments (Anonymous)                 |
| `pageInfo`         | `PageInfo`       | No       | Information about the page                                 |


# null



## `RecorderConfig` Class

| Property          | Type                                                     | Optional | Description                    |
| ----------------- | -------------------------------------------------------- | -------- | ------------------------------ |
| `type`            | `{ audio?: boolean, video?: boolean, screen?: boolean }` | No       | Types of media to be recorded  |
| `recorderOptions` | MediaRecorderOptions                                     | Yes      | Options for the media recorder |

## `RecordedData` Class

| Property                   | Type     | Optional | Description                                                                                        |
| -------------------------- | -------- | -------- | -------------------------------------------------------------------------------------------------- |
| `id`                       | string   | No       | Annotation ID of recorder annotation.                                                              |
| `tag`                      | string   | No       | Recorder player tag containing recorder annotation id which can be added anywhere on the DOM.      |
| `type`                     | string   | No       | Type of recorded data. Possible values are 'audio', 'video', and 'screen'.                         |
| `thumbnailUrl`             | string   | Yes      | URL of the thumbnail image for the recorded data.                                                  |
| `thumbnailWithPlayIconUrl` | string   | Yes      | URL of the thumbnail image with a play icon overlay.                                               |
| `videoUrl`                 | string   | Yes      | URL of the recorded video.                                                                         |
| `audioUrl`                 | string   | Yes      | URL of the recorded audio.                                                                         |
| `videoPlayerUrl`           | string   | Yes      | URL of the hosted website to open video in a new tab.                                              |
| `getThumbnailTag`          | function | No       | A method that returns an HTML string for displaying the thumbnail with a link to the video player. |

### `getThumbnailTag` Method

The `getThumbnailTag` method takes an optional `url` parameter and returns an HTML string. It creates an anchor tag linking to the `videoPlayerUrl` and embeds an image tag using either the provided `url`, `thumbnailWithPlayIconUrl`, or `thumbnailUrl` (in that order of preference).


# RecorderAnnotation



## `RecorderAnnotation` Class Properties

| Property          | Type          | Optional | Description                                                             |   |
| ----------------- | ------------- | -------- | ----------------------------------------------------------------------- | - |
| `annotationId`    | String        | No       | Unique identifier for the recorder annotation, automatically generated. |   |
| `from`            | `User`        | No       | The user who created the recorder annotation.                           |   |
| `color`           | String        | Yes      | Color used for the annotation.                                          |   |
| `lastUpdated`     | Any           | Yes      | Timestamp of the last update, automatically generated.                  |   |
| `locationId`      | Number        | Yes      | Unique location ID from provided location.                              |   |
| `location`        | `Location`    | Yes      | Location to identify user on sub document.                              |   |
| `type`            | String        | Yes      | Type of annotation.                                                     |   |
| `recordingType`   | String        | No       | Type of recording for the annotation.                                   |   |
| `mode`            | String        | No       | Mode of the recorder annotation, 'floating' or 'thread'.                |   |
| `approved`        | Boolean       | Yes      | Indicates if the annotation is approved.                                |   |
| `attachment`      | Attachment    | Yes      | Attachment for recorded media. Deprecated.                              |   |
| `attachments`     | Attachment\[] | No       | List of attachments for the annotation.                                 |   |
| `annotationIndex` | Number        | Yes      | Index of the annotation in a list.                                      |   |
| `pageInfo`        | PageInfo      | Yes      | Information about the page where the annotation is made.                |   |
| `recordedTime`    | Object        | Yes      | Recorded time details.                                                  |   |
| `transcription`   | Transcription | Yes      | Transcription of the recorded media.                                    |   |


# RecorderData



## `RecorderDataTranscriptSegment` Class Properties

| Property             | Type   | Optional | Description                             |
| -------------------- | ------ | -------- | --------------------------------------- |
| `startTime`          | String | No       | Start time of the transcription segment |
| `endTime`            | String | No       | End time of the transcription segment   |
| `startTimeInSeconds` | Number | No       | Start time of the segment in seconds    |
| `endTimeInSeconds`   | Number | No       | End time of the segment in seconds      |
| `text`               | String | No       | Transcribed text content of the segment |

## `RecorderDataTranscription` Class Properties

| Property             | Type                              | Optional | Description                              |
| -------------------- | --------------------------------- | -------- | ---------------------------------------- |
| `transcriptSegments` | `RecorderDataTranscriptSegment[]` | Yes      | Array of transcription segments          |
| `vttFileUrl`         | String                            | Yes      | URL to the VTT format transcription file |
| `contentSummary`     | String                            | Yes      | Summary of the transcribed content       |

## `RecorderDataAsset` Class Properties

| Property          | Type                               | Optional | Description                        |
| ----------------- | ---------------------------------- | -------- | ---------------------------------- |
| `url`             | String                             | No       | URL to the recorded media          |
| `mimeType`        | String                             | Yes      | MIME type of the recorded media    |
| `fileName`        | String                             | Yes      | Name of the recorded file          |
| `fileSizeInBytes` | Number                             | Yes      | Size of the recorded file in bytes |
| `fileFormat`      | 'mp3' \| 'mp4' \| 'webm' \| String | Yes      | The format/extension of the file   |
| `thumbnailUrl`    | String                             | Yes      | URL to the thumbnail image         |

## `RecorderData` Class Properties

| Property        | Type                        | Optional | Description                                       |
| --------------- | --------------------------- | -------- | ------------------------------------------------- |
| `assets`        | `RecorderDataAsset[]`       | No       | Array of recording assets with metadata           |
| `transcription` | `RecorderDataTranscription` | No       | Transcription data including segments and summary |


# RewriterAnnotation



## `RewriterAnnotation` Class Properties

| Property                 | Type                    | Optional | Description                                                                           |
| ------------------------ | ----------------------- | -------- | ------------------------------------------------------------------------------------- |
| `annotationId`           | String                  | No       | Unique identifier for the rewriter annotation, automatically generated.               |
| `from`                   | `User`                  | No       | The user who created this rewriter annotation.                                        |
| `color`                  | String                  | Yes      | Color used for the rewriter annotation.                                               |
| `lastUpdated`            | Any                     | Yes      | Timestamp when the rewriter annotation was last updated, automatically generated.     |
| `documentParamsId`       | Number \| null          | Yes      | Unique document params ID, deprecated, use `locationId` instead.                      |
| `documentParams`         | `Location` \| null      | Yes      | Document params to identify user on sub document, deprecated, use `location` instead. |
| `locationId`             | Number \| null          | Yes      | Unique location ID generated from provided location.                                  |
| `location`               | Location \| null        | Yes      | Set location to identify user on sub document.                                        |
| `type`                   | String                  | Yes      | Type of annotation.                                                                   |
| `rewriterType`           | String                  | No       | Type of rewriter for the annotation, either 'generic' or 'copywriter'.                |
| `targetTextRange`        | TargetTextRange \| null | Yes      | Selected text range of rewriter annotation.                                           |
| `annotationIndex`        | Number                  | Yes      | Index of the current annotation in the list of annotations.                           |
| `pageInfo`               | `PageInfo`              | Yes      | Information about the page where the annotation is made.                              |
| `selectedRewriterOption` | String                  | Yes      | Selected rewriter option used in the annotation.                                      |


# SyncVideoPlayer



## `SyncVideoPlayer` Class Properties

| Property           | Type                 | Optional | Description                                           |
| ------------------ | -------------------- | -------- | ----------------------------------------------------- |
| `playerId`         | String               | Yes      | The identifier for the video player instance.         |
| `src`              | String               | Yes      | The source URL of the video.                          |
| `sources`          | String\[]            | Yes      | An array of source URLs for the video.                |
| `lastUpdated`      | Number               | Yes      | The timestamp of when the player was last updated.    |
| `lastUpdatedBy`    | `User`               | Yes      | The user who last updated the player.                 |
| `lastUpdatedEvent` | String               | Yes      | The name of the event that triggered the last update. |
| `playerState`      | SyncVideoPlayerState | No       | The state object of the video player.                 |

## `SyncVideoPlayerState` Class Properties

| Property      | Type    | Optional | Description                                  |
| ------------- | ------- | -------- | -------------------------------------------- |
| `playing`     | Boolean | Yes      | Indicates if the video is currently playing. |
| `currentTime` | Number  | Yes      | The current playback time of the video.      |
| `muted`       | Boolean | Yes      | Indicates if the video is muted.             |
| `volume`      | Number  | Yes      | The volume level of the video.               |
| `speed`       | Number  | Yes      | The playback rate of the video.              |


# null



## `Toast` Class Properties

| Property   | Type                 | Optional | Default Value | Description                                                              |
| ---------- | -------------------- | -------- | ------------- | ------------------------------------------------------------------------ |
| `id`       | Number               | Yes      | None          | A unique identifier for the toast notification.                          |
| `message`  | String               | No       | None          | The message content displayed in the toast notification.                 |
| `type`     | 'success' \| 'error' | No       | None          | The type of toast notification, indicating success or error.             |
| `duration` | Number               | Yes      | 3000          | The length of time the toast notification is displayed, in milliseconds. |


# null



## `Transcription` Class Properties

| Property           | Type   | Optional | Description                                           |
| ------------------ | ------ | -------- | ----------------------------------------------------- |
| `from`             | User   | No       | The user who created the transcription.               |
| `lastUpdated`      | Number | Yes      | Timestamp of when the transcription was last updated. |
| `transcriptedText` | String | Yes      | The text that has been transcribed.                   |


# null



## `User` Class Properties

| Property               | Type    | Optional | Description                                                                                                                       |
| ---------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `userId`               | string  | No       | Unique user identifier used to identify your user.                                                                                |
| `name`                 | string  | Yes      | The full name of your user. Defaults to a random avatar name if not provided.                                                     |
| `photoUrl`             | string  | Yes      | The display picture URL of your user. Defaults to a random avatar image if not provided.                                          |
| `email`                | string  | Yes      | Required for sending email or Slack notifications to users about comments and mentions.                                           |
| `plan`                 | string  | Yes      | The product plan the user is on.                                                                                                  |
| `organizationId`       | string  | Yes      | Autogenerated organizationId based on the organizationId you provide.                                                             |
| `clientorganizationId` | string  | Yes      | The original organizationId provided by you.                                                                                      |
| `color`                | string  | Yes      | A color assigned to the user for the current session, used for avatar border, live cursor, selection etc.                         |
| `textColor`            | string  | Yes      | Used in the text color of the user's intial when photoUrl is not present.                                                         |
| `type`                 | string  | Yes      | The type of user.                                                                                                                 |
| `isReadOnly`           | boolean | Yes      | Indicates if the user has read-only access.                                                                                       |
| `isAnonymous`          | boolean | Yes      | Indicates if the user is anonymous and can only view comments.                                                                    |
| `isGuest`              | boolean | Yes      | Indicates if the user is a guest.                                                                                                 |
| `isAdmin`              | boolean | Yes      | Use this to set the user as an admin. You also need to ensure that the jwt token you generate also has this property set to true. |
| `groupId`              | string  | Yes      | \[DEPRECATED] A domain name or identifier used to cluster a group of users who work together.                                     |
| `clientGroupId`        | string  | Yes      | \[DEPRECATED] The original groupId provided by the user.                                                                          |
| `initial`              | string  | Yes      | First letter of the user's first name.                                                                                            |

## `UserOptions` Class Properties

| Property          | Type    | Optional | Description                                                                                    |
| ----------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- |
| `replaceContacts` | boolean | Yes      | If set to true, it will replace the user's personal and group contacts with the ones provided. |
| `authToken`       | string  | Yes      | The authentication token of the user.                                                          |


# UserContactSelectedPayload



| Property                | Type        | Optional | Description                           |
| ----------------------- | ----------- | -------- | ------------------------------------- |
| `contact`               | UserContact | No       | Selected user contact details.        |
| `isOrganizationContact` | boolean     | No       | Is user part of organization contact. |
| `isDocumentContact`     | boolean     | No       | Is user part of document contact.     |
| `documentAccessType`    | string      | No       | Document access type.                 |


# UserContactUs



## `UserContactUs` Class Properties

| Property      | Type                         | Optional | Description                                      |
| ------------- | ---------------------------- | -------- | ------------------------------------------------ |
| `id`          | `string`                     | Yes      | Unique identifier of the feedback.               |
| `apiKey`      | `string` \| `null`           | Yes      | API key of the client.                           |
| `emailId`     | `string`                     | Yes      | Email address of the feedback provider.          |
| `message`     | `string`                     | Yes      | Content of the user's feedback message.          |
| `from`        | `User` \| `null`             | Yes      | User who submitted the feedback.                 |
| `lastUpdated` | `any`                        | Yes      | Timestamp of when the feedback was last updated. |
| `metadata`    | `DocumentMetadata` \| `null` | Yes      | Metadata associated with the document.           |
| `pageInfo`    | `PageInfo`                   | Yes      | Information about the user's current page.       |


# UserFeedback



## `UserFeedback` Class Properties

| Property      | Type                         | Optional | Description                                      |
| ------------- | ---------------------------- | -------- | ------------------------------------------------ |
| `id`          | `string`                     | Yes      | Unique identifier of the feedback.               |
| `apiKey`      | `string` \| `null`           | Yes      | API key of the client.                           |
| `emailId`     | `string`                     | Yes      | Email address of the feedback provider.          |
| `message`     | `string`                     | Yes      | Content of the user's feedback message.          |
| `from`        | `User` \| `null`             | Yes      | User who submitted the feedback.                 |
| `lastUpdated` | `any`                        | Yes      | Timestamp of when the feedback was last updated. |
| `metadata`    | `DocumentMetadata` \| `null` | Yes      | Metadata associated with the document.           |
| `pageInfo`    | `PageInfo`                   | Yes      | Information about the user's current page.       |


# Add Comment Annotations

POST https://api.velt.dev/v1/commentannotations/add

Use this API to add comment annotations to a document within an organization.

*   You can add comments on an elemement, text or page.
*   You can provide HTML or text content.
*   Additional filters can be applied using location IDs.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="Object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="commentAnnotations" type="Object[]" required>
      <Expandable title="properties">
        <ParamField body="location" type="Object">
          <Expandable title="properties">
            <ParamField body="id" type="string" required>
              Location ID
            </ParamField>

            <ParamField body="locationName" type="string">
              Location Name
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="targetElement" type="Object">
          Target Element

          <Expandable title="properties">
            <ParamField body="elementId" type="string">
              Element DOM Id
            </ParamField>

            <ParamField body="targetText" type="string">
              Target Text. Provide this if you want to add comment annotation on the provided text content.
            </ParamField>

            <ParamField body="occurrence" type="number">
              Occurrence. Provide this if you want to add comment annotation on a text content.
            </ParamField>

            <ParamField body="selectAllContent" type="boolean">
              Select All Content. Provide this if you want to select and add comment annotation on the entire text content of the target elementId.
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="commentData" type="Object[]" required>
          Array of Comment Data

          <Expandable title="properties">
            <ParamField body="commentText" type="string">
              Comment content in plain text string
            </ParamField>

            <ParamField body="commentHtml" type="string">
              Comment content in HTML string
            </ParamField>

            <ParamField body="from" type="User" required>
              User object from whom the comment is added
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="status" type="Status">
          Status

          <Expandable title="properties">
            <ParamField body="type" type="string" required>
              Type

              <Expandable title="properties">
                <ParamField body="default" type="boolean" required>
                  Default
                </ParamField>

                <ParamField body="ongoing" type="boolean" required>
                  Ongoing
                </ParamField>

                <ParamField body="terminal" type="boolean" required>
                  Terminal
                </ParamField>
              </Expandable>
            </ParamField>

            <ParamField body="lightColor" type="string" required>
              Light Color
            </ParamField>

            <ParamField body="svg" type="string" required>
              Raw SVG of the icon
            </ParamField>

            <ParamField body="iconUrl" type="string" required>
              Icon URL
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="assignedTo" type="User">
          User object to whom the comment is assigned
        </ParamField>

        <ParamField body="context" type="Object">
          Custom key/value metadata object
        </ParamField>

        <ParamField body="priority" type="Object">
          Priority

          <Expandable title="properties">
            <ParamField body="id" type="string" required>
              Priority ID
            </ParamField>

            <ParamField body="color" type="string" required>
              Priority Color
            </ParamField>

            <ParamField body="name" type="string" required>
              Priority Name
            </ParamField>

            <ParamField body="lightColor" type="string" required>
              Priority Light Color
            </ParamField>
          </Expandable>
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### Add comment annotation by organizationId, documentId and location

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "commentAnnotations": [
      {
        "location": {
          "id": "yourLocationId",
          "locationName": "yourLocationName"
        },
        "targetElement": {
          "elementId": "yourElementId",
          "targetText": "Your Target Text",
          "occurrence": 1,
          "selectAllContent": false
        },
        "commentData": [
          {
            "commentText": "Sample Comment",
            "commentHtml": "<div>Hello</div>",
            "from": {
              "userId": "yourUserId",
              "name": "yourUserName",
              "email": "yourUserEmail",
            }
          }
        ]
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
   "result": {
       "status": "success",
       "message": "Comment Annotation addition successfully.",
       "data": {
           "-O0mpUziLcBwzREvZKs6": {
               "success": true,
               "annotationId": "-O0mpUziLcBwzREvZKs6",
               "commentIds": [
                   126535
               ],
               "message": "Added Successfully"
           }
       }
   }
}

```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Comment Annotation addition successful.",
      "data": {
        "annotationId": "yourAnnotationId",
        "commentIds": [
          333130
        ]
      }
    }
  }
  ```
</ResponseExample>


# Delete Comment Annotations

POST https://api.velt.dev/v1/commentannotations/delete

Use this API to delete comment annotations from a document within an organization.
Additional filters can be applied using location IDs, annotation IDs, or user IDs.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string">
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="locationIds" type="string[]">
      Array of Location IDs
    </ParamField>

    <ParamField body="annotationIds" type="string[]">
      Array of Annotation IDs
    </ParamField>

    <ParamField body="userIds" type="string[]">
      Array of User IDs
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Delete annotations by organizationId and documentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId"
  }
}
```

#### 2. Delete annotations by organizationId, documentId and locationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ]
  }
}
```

#### 3. Delete annotations by organizationId, documentId, locationIds and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "userIds": [
      "yourUserId"
    ]
  }
}
```

#### 4. Delete annotations by organizationId, documentId and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId"
    ]
  }
}
```

#### 5. Delete annotations by organizationId, documentId and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ]
  }
}
```

#### 6. Delete annotations by organizationId, documentId, locationIds and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ]
  }
}
```

#### 7. Delete annotations by documentId. This will work if the document was created without an organization.

```JSON
{
  "data": {
    "documentId": "yourDocumentId"
  }
}
```

#### 8. Delete annotations by documentId and locationIds. This will work if the document was created without an organization.

```JSON
{
  "data": {
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ]
  }
}
```

#### 9. Delete annotations by documentId and userIds. This will work if the document was created without an organization.

```JSON
{
  "data": {
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId"
    ]
  }
}
```

#### 10. Delete annotations by documentId and annotationIds. This will work if the document was created without an organization.

```JSON
{
  "data": {
    "documentId": "yourDocumentId",
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ]
  }
}
```

#### 11. Delete annotations by documentId, locationIds, and userIds. This will work if the document was created without an organization.

```JSON
{
  "data": {
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "userIds": [
      "yourUserId"
    ]
  }
}
```

#### 12. Delete annotations by documentId, locationIds, and annotationIds. This will work if the document was created without an organization.

```JSON
{
  "data": {
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Annotations deleted successfully.",
    "data": {
      "yourAnnotationId1": {
        "success": true,
        "id": "yourAnnotationId",
        "message": "Deleted Successfully"
      },
      "yourAnnotationId2": {
        "success": false,
        "id": "yourAnnotationId2",
        "message": "Annotation not found."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Annotations deleted successfully.",
      "data": {
        "yourAnnotationId": {
          "success": true,
          "id": "yourAnnotationId",
          "message": "Deleted Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Get Comment Annotations

POST https://api.velt.dev/v1/commentannotations/get

Use this API to retrieve comment annotations from a document within an organization.
Additional filters can be applied using location IDs, annotation IDs, or user IDs.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="locationIds" type="string[]">
      Array of Location IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>

    <ParamField body="annotationIds" type="string[]">
      Array of Annotation IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>

    <ParamField body="userIds" type="string[]">
      Array of User IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get annotations by organizationId and documentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
  }
}
```

#### 2. Get annotations by organizationId, documentId, and locationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
  }
}
```

#### 3. Get annotations by organizationId, documentId, locationIds, and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "userIds": [
      "yourUserId"
    ],
  }
}
```

#### 4. Get annotations by organizationId, documentId, and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId"
    ],
  }
}
```

#### 5. Get annotations by organizationId, documentId, and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ],
  }
}
```

#### 6. Get annotations by organizationId, documentId, locationIds, and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ],
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Annotations fetched successfully.",
    "data": [
      {
        "annotationId": "yourAnnotationId",
        "comments": [
          {
            "commentId": 123456,
            "commentText": "This is a sample comment text.",
            "commentHtml": "<p>This is a sample comment text.</p>",
            "from": {
              "userId": "user123",
              "name": "John Doe",
              "email": "john.doe@example.com"
            },
            "lastUpdated": "2023-06-15T10:30:00Z"
          }
        ],
        "from": {
          "userId": "user123",
          "name": "John Doe",
          "email": "john.doe@example.com"
        },
        "color": "#00FF00",
        "createdAt": "2023-06-15T10:30:00Z",
        "lastUpdated": "2023-06-15T10:30:00Z",
        "status": {
          "id": "OPEN",
          "name": "Open",
          "color": "#0000FF",
          "type": "default"
        }
      },
      null // null is returned only if you provided an annotationId that doesn't exist
    ]
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Annotations fetched successfully.",
      "data": [
        {
          "annotationId": "yourAnnotationId",
          "comments": [
            {
              "commentId": 123456,
              "commentText": "This is a sample comment text.",
              "commentHtml": "<p>This is a sample comment text.</p>",
              "from": {
                "userId": "user123",
                "name": "John Doe",
                "email": "john.doe@example.com"
              },
              "lastUpdated": "2023-06-15T10:30:00Z",
              "type": "text",
            }
          ],
          "from": {
            "userId": "user123",
            "name": "John Doe",
            "email": "john.doe@example.com"
          },
          "color": "#00FF00",
          "createdAt": "2023-06-15T10:30:00Z",
          "lastUpdated": "2023-06-15T10:30:00Z",
          "status": {
            "id": "OPEN",
            "name": "Open",
            "color": "#0000FF",
            "type": "default"
          }
        },
        null // null is returned only if you provided an annotationId that doesn't exist
      ]
    }
  }
  ```
</ResponseExample>


# Get Comment Annotations v2

POST https://api.velt.dev/v2/commentannotations/get

Use this API to retrieve comment annotations from a document within an organization.
Additional filters can be applied using location IDs, annotation IDs, or user IDs.

# Endpoint

`POST https://api.velt.dev/v2/commentannotations/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="locationIds" type="string[]">
      Array of Location IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>

    <ParamField body="annotationIds" type="string[]">
      Array of Annotation IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>

    <ParamField body="userIds" type="string[]">
      Array of User IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>

    <ParamField body="pageSize" type="number">
      Number of items to be retrieved per page. Default: 1000.
    </ParamField>

    <ParamField body="pageToken" type="string">
      Page token retrieved from previous API call.
    </ParamField>

    <ParamField body="order" type="'asc' | 'desc'">
      Order of results based on `lastUpdated` timestamp. Options: `asc` or `desc`. Default: `desc`.
    </ParamField>

    <ParamField body="statusId" type="string">
      Status ID of the annotations to filter on.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get annotations by organizationId and documentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "pageSize": 10,
    "pageToken": "1720441573192",
    "statusId": "OPEN"
  }
}
```

#### 2. Get annotations by organizationId, documentId, and locationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "pageSize": 10,
    "pageToken": "1720441573192",
    "statusId": "OPEN"
  }
}
```

#### 3. Get annotations by organizationId, documentId, locationIds, and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "userIds": [
      "yourUserId"
    ],
    "pageSize": 10,
    "pageToken": "1720441573192",
    "statusId": "OPEN"
  }
}
```

#### 4. Get annotations by organizationId, documentId, and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId"
    ],
    "pageSize": 10,
    "pageToken": "1720441573192",
    "statusId": "OPEN"
  }
}
```

#### 5. Get annotations by organizationId, documentId, and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ],
    "pageSize": 10,
    "pageToken": "1720441573192",
    "statusId": "OPEN"
  }
}
```

#### 6. Get annotations by organizationId, documentId, locationIds, and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ],
    "pageSize": 10,
    "pageToken": "1720441573192",
    "statusId": "OPEN"
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Annotations fetched successfully.",
    "data": [
      {
        "annotationId": "yourAnnotationId",
        "comments": [
          {
            "commentId": 123456,
            "commentText": "This is a sample comment text.",
            "commentHtml": "<p>This is a sample comment text.</p>",
            "from": {
              "userId": "user123",
              "name": "John Doe",
              "email": "john.doe@example.com"
            },
            "lastUpdated": "2023-06-15T10:30:00Z"
          }
        ],
        "from": {
          "userId": "user123",
          "name": "John Doe",
          "email": "john.doe@example.com"
        },
        "color": "#00FF00",
        "createdAt": "2023-06-15T10:30:00Z",
        "lastUpdated": "2023-06-15T10:30:00Z",
        "status": {
          "id": "OPEN",
          "name": "Open",
          "color": "#0000FF",
          "type": "default"
        }
      },
      null // null is returned only if you provided an annotationId that doesn't exist
    ],
    "nextPageToken": "pageToken"
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Annotations fetched successfully.",
      "data": [
        {
          "annotationId": "yourAnnotationId",
          "comments": [
            {
              "commentId": 123456,
              "commentText": "This is a sample comment text.",
              "commentHtml": "<p>This is a sample comment text.</p>",
              "from": {
                "userId": "user123",
                "name": "John Doe",
                "email": "john.doe@example.com"
              },
              "lastUpdated": "2023-06-15T10:30:00Z",
              "type": "text",
            }
          ],
          "from": {
            "userId": "user123",
            "name": "John Doe",
            "email": "john.doe@example.com"
          },
          "color": "#00FF00",
          "createdAt": "2023-06-15T10:30:00Z",
          "lastUpdated": "2023-06-15T10:30:00Z",
          "status": {
            "id": "OPEN",
            "name": "Open",
            "color": "#0000FF",
            "type": "default"
          }
        },
        null // null is returned only if you provided an annotationId that doesn't exist
      ],
      "nextPageToken": "pageToken"
    }
  }
  ```
</ResponseExample>


# Update Comment Annotations

POST https://api.velt.dev/v1/commentannotations/update

Use this API to update comment annotations in a document within an organization.
Additional filters can be applied using location IDs, annotation IDs, or user IDs.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="locationIds" type="string[]">
      Array of Location IDs
    </ParamField>

    <ParamField body="userIds" type="string[]">
      Array of User IDs. These are the users who created the comment annotation.
    </ParamField>

    <ParamField body="annotationIds" type="string[]">
      Array of Annotation IDs
    </ParamField>

    <ParamField body="updatedData" type="Object[]" required>
      <Expandable title="properties">
        <ParamField body="location" type="Object">
          <Expandable title="properties">
            <ParamField body="id" type="string" required>
              Location ID
            </ParamField>

            <ParamField body="locationName" type="string">
              Location Name
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="targetElement" type="Object">
          Target Element

          <Expandable title="properties">
            <ParamField body="elementId" type="string">
              Element DOM Id
            </ParamField>

            <ParamField body="targetText" type="string">
              Target Text. Provide this if you want to add comment annotation on the provided text content.
            </ParamField>

            <ParamField body="occurrence" type="number">
              Occurrence. Provide this if you want to add comment annotation on a text content.
            </ParamField>

            <ParamField body="selectAllContent" type="boolean">
              Select All Content. Provide this if you want to select and add comment annotation on the entire text content of the target elementId.
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="commentData" type="Object[]" required>
          Array of Comment Data

          <Expandable title="properties">
            <ParamField body="commentText" type="string">
              Comment content in plain text string
            </ParamField>

            <ParamField body="commentHtml" type="string">
              Comment content in HTML string
            </ParamField>

            <ParamField body="from" type="User" required>
              User object from whom the comment is added
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="from" type="User" required>
          User object from whom the Comment Annotation is added
        </ParamField>

        <ParamField body="status" type="Status">
          Status

          <Expandable title="properties">
            <ParamField body="type" type="string" required>
              Type

              <Expandable title="properties">
                <ParamField body="default" type="boolean" required>
                  Default
                </ParamField>

                <ParamField body="ongoing" type="boolean" required>
                  Ongoing
                </ParamField>

                <ParamField body="terminal" type="boolean" required>
                  Terminal
                </ParamField>
              </Expandable>
            </ParamField>

            <ParamField body="lightColor" type="string" required>
              Light Color
            </ParamField>

            <ParamField body="svg" type="string" required>
              Raw SVG of the icon
            </ParamField>

            <ParamField body="iconUrl" type="string" required>
              Icon URL
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="assignedTo" type="User">
          User object to whom the comment is assigned
        </ParamField>

        <ParamField body="context" type="Object">
          Custom key/value metadata object
        </ParamField>

        <ParamField body="priority" type="Object">
          Priority

          <Expandable title="properties">
            <ParamField body="id" type="string" required>
              Priority ID
            </ParamField>

            <ParamField body="color" type="string" required>
              Priority Color
            </ParamField>

            <ParamField body="name" type="string" required>
              Priority Name
            </ParamField>

            <ParamField body="lightColor" type="string" required>
              Priority Light Color
            </ParamField>
          </Expandable>
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Update all comment annotations by organizationId and documentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "updatedData" : {
      "status": {
        "type": "ongoing"
      }
    }
  }
}
```

#### 2. Update comment annotations by organizationId, documentId and locationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "updatedData" : {
      "status": {
        "type": "ongoing"
      }
    }
  }
}
```

#### 3. Update annotations by organizationId, documentId, locationIds and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "userIds": [
      "yourUserId"
    ],
    "updatedData" : {
      "status": {
        "type": "ongoing"
      }
    }
  }
}
```

#### 4. Update comment annotations by organizationId, documentId and userIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId"
    ],
    "updatedData" : {
      "status": {
        "type": "ongoing"
      }
    }
  }
}
```

#### 5. Update comment annotations by organizationId, documentId and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ],
    "updatedData" : {
      "status": {
        "type": "ongoing"
      }
    }
  }
}
```

#### 6. Update comment annotations by organizationId, documentId, locationIds and annotationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationIds": [
      "locationx"
    ],
    "annotationIds": [
      "yourAnnotationId1",
      "yourAnnotationId2"
    ],
    "updatedData" : {
      "status": {
        "type": "ongoing"
      }
    }
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Annotations updated successfully.",
    "data": [
      "yourAnnotationId1",
      "yourAnnotationId2",
      "yourAnnotationId3",
      "yourAnnotationId4",
      "yourAnnotationId5",
      "yourAnnotationId6",
      "yourAnnotationId7"
    ]
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Annotations updated successfully.",
      "data": [
        "yourAnnotationId1",
        "yourAnnotationId2",
        "yourAnnotationId3",
        "yourAnnotationId4",
        "yourAnnotationId5",
        "yourAnnotationId6",
        "yourAnnotationId7"
      ]
    }
  }
  ```
</ResponseExample>


# Add Comments

POST https://api.velt.dev/v1/commentannotations/comments/add

Use this API to add comments within a specific CommentAnnotation.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/comments/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="annotationId" type="string" required>
      Comment Annotation ID
    </ParamField>

    <ParamField body="commentData" type="Comment[]" required>
      Array of Comment Data

      <Expandable title="properties">
        <ParamField body="commentText" type="string">
          Comment content in plain text string
        </ParamField>

        <ParamField body="commentHtml" type="string">
          Comment content in HTML string
        </ParamField>

        <ParamField body="from" type="User" required>
          User object from whom the comment is added
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Add comment in a CommentAnnotation by organizationId, documentId, and annotationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationId": "yourAnnotationId",
    "commentData": [
      {
        "commentText": "Sample Comment",
        "commentHtml": "<div>Hello</div>",
        "from": {
          "userId": "yourUserId"
        }
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Comment(s) added successfully.",
    "data": [
      778115
    ]
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Comment(s) added successfully.",
      "data": [
        778115
      ]
    }
  }
  ```
</ResponseExample>


# Delete Comments

POST https://api.velt.dev/v1/commentannotations/comments/delete

Use this API to delete comments within a specific CommentAnnotation.
Additional filters can be applied using comment IDs.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/comments/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="annotationId" type="string" required>
      Comment Annotation ID
    </ParamField>

    <ParamField body="commentIds" type="number[]">
      Array of Comment IDs
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Delete all comments of a CommentAnnotation by organizationId, documentId, and annotationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationId": "yourAnnotationId"
  }
}
```

#### 2. Delete specific comments of a CommentAnnotation by organizationId, documentId, annotationId and commentIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationId": "yourAnnotationId",
    "commentIds": [
      153783,
      607395
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Comments(s) deleted successfully.",
    "data": {
      "153783": {
        "success": true,
        "id": 153783,
        "message": "Deleted successfully"
      },
      "607395": {
        "success": false,
        "id": 607395,
        "message": "Not found"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Comments(s) deleted successfully.",
      "data": {
        "153783": {
          "success": true,
          "id": 153783,
          "message": "Deleted successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Get Comments

POST https://api.velt.dev/v1/commentannotations/comments/get

Use this API to retrieve comments in a specific CommentAnnotation.
Additional filters can be applied using comment IDs.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/comments/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="annotationId" type="string" required>
      Comment Annotation ID
    </ParamField>

    <ParamField body="userIds" type="string[]" required>
      User IDs
    </ParamField>

    <ParamField body="commentIds" type="number[]">
      Array of Comment IDs
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get all comments with a CommentAnnotation by organizationId, documentId, and annotationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationId": "yourAnnotationId"
  }
}
```

#### 2. Get specific comments of a CommentAnnotation by organizationId, documentId, annotationId and commentIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationId": "yourAnnotationId",
    "commentIds": [
      153783,
      607395
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Comments(s) retrieved successfully.",
    "data": [
      {
        "commentHtml": "<div>Hello Updated 2</div>",
        "commentId": 153783,
        "commentText": "Sample Comment Text",
        "from": {
          "email": "user@example.com",
          "name": "User Name",
          "userId": "yourUserId"
        },
        "lastUpdated": "2024-06-20T09:53:42.258Z",
        "status": "added",
        "type": "text"
      },
      null // If comment not found
    ]
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Comments(s) retrieved successfully.",
      "data": [
        {
          "commentHtml": "<div>Hello Updated 2</div>",
          "commentId": 153783,
          "commentText": "Sample Comment Text",
          "from": {
            "email": "user@example.com",
            "name": "User Name",
            "userId": "yourUserId"
          },
          "lastUpdated": "2024-06-20T09:53:42.258Z",
          "status": "added",
          "type": "text"
        }
      ]
    }
  }
  ```
</ResponseExample>


# Update Comments

POST https://api.velt.dev/v1/commentannotations/comments/update

Use this API to update comments within a specific CommentAnnotation.

# Endpoint

`POST https://api.velt.dev/v1/commentannotations/comments/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="annotationId" type="string" required>
      Comment Annotation ID
    </ParamField>

    <ParamField body="annotationId" type="number[]" required>
      Comment IDs
    </ParamField>

    <ParamField body="updatedData" type="Object" required>
      Comment data

      <Expandable title="properties">
        <ParamField body="commentText" type="string">
          Comment content in plain text string
        </ParamField>

        <ParamField body="commentHtml" type="string">
          Comment content in HTML string
        </ParamField>

        <ParamField body="from" type="User" required>
          User object from whom the comment is added
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### Update comment in a CommentAnnotation by organizationId, documentId, annotationId and commentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "annotationId": "yourAnnotationId",
    "commentIds": [
      153783,
      607395
    ],
    "updatedData": {
      "commentText": "Sample Updated Comment",
      "commentHtml": "<div>Hello Updated</div>"
    }
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Comment updated successfully.",
    "data": {
      "607395": {
        "success": true,
        "id": 607395,
        "message": "Updated successfully"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Comment updated successfully.",
      "data": {
        "607395": {
          "success": true,
          "id": 607395,
          "message": "Updated successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Add Documents

POST https://api.velt.dev/v1/organizations/documents/add

Use this API to add documents with metadata to an organization.

# Endpoint

`POST https://api.velt.dev/v1/organizations/documents/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documents" type="Document[]" required>
      Array of Document objects
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documents": [
      {
        "documentId": "yourDocumentId",
        "documentName": "Your Document Name"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Document(s) added successfully.",
    "data": {
      "yourDocumentId": {
        "success": true,
        "id": "8121657101517513",
        "message": "Added Successfully"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Document(s) added successfully.",
      "data": {
        "yourDocumentId": {
          "success": true,
          "id": "8121657101517513",
          "message": "Added Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Delete Documents

POST https://api.velt.dev/v1/organizations/documents/delete

Use this API to delete specific documents from an organization.

# Endpoint

`POST https://api.velt.dev/v1/organizations/documents/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentIds" type="string[]" required>
      Array of Document IDs
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentIds": ["yourDocumentId1", "yourDocumentId2"]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Document(s) deleted successfully.",
    "data": {
      "yourDocumentId1": {
        "success": true,
        "id": "6737987049068973",
        "message": "Deleted Successfully"
      },
      "yourDocumentId2": {
        "success": true,
        "id": "2131443384150904",
        "message": "Document does not exist"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Document(s) deleted successfully.",
      "data": {
        "yourDocumentId1": {
          "success": true,
          "id": "6737987049068973",
          "message": "Deleted Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Get Documents

POST https://api.velt.dev/v1/organizations/documents/get

Use this API to retrieve specific documents or all documents from an organization.

# Endpoint

`POST https://api.velt.dev/v1/organizations/documents/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentIds" type="string[]">
      Array of Document IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get all documents from organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
  }
}
```

#### 2. Get specific documents from organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentIds": ["yourDocumentId1", "yourDocumentId2"],
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Document(s) retrieved successfully.",
    "data": [
      {
        "documentName": "yourDocumentName",
        "disabled": false,
        "accessType": "public",
        "id": "yourDocumentId",
      }
    ]
  }
}

```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Document(s) retrieved successfully.",
      "data": [
        {
          "documentName": "yourDocumentName",
          "disabled": false,
          "accessType": "public",
          "id": "yourDocumentId",
        }
      ]
    }
  }
  ```
</ResponseExample>


# Get Documents v2

POST https://api.velt.dev/v2/organizations/documents/get

Use this API to retrieve specific documents or all documents from an organization.

# Endpoint

`POST https://api.velt.dev/v2/organizations/documents/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentIds" type="string[]">
      Array of Document IDs. Limit: Only 30 IDs can be passed at a time.
    </ParamField>

    <ParamField body="pageSize" type="number">
      Number of items to be retrieved per page. Default: 1000.
    </ParamField>

    <ParamField body="pageToken" type="string">
      Page token retrieved from previous API call.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get all documents from organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "pageSize": 20,
    "pageToken": "8740648311207869"
  }
}
```

#### 2. Get specific documents from organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentIds": ["yourDocumentId1", "yourDocumentId2"],
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Document(s) retrieved successfully.",
    "data": [
      {
        "documentName": "yourDocumentName",
        "disabled": false,
        "accessType": "public",
        "id": "yourDocumentId",
      }
    ],
    "pageToken": "nextPageToken"
  }
}

```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Document(s) retrieved successfully.",
      "data": [
        {
          "documentName": "yourDocumentName",
          "disabled": false,
          "accessType": "public",
          "id": "yourDocumentId",
        }
      ],
      "pageToken": "nextPageToken"
    }
  }
  ```
</ResponseExample>


# Update Access for Documents

POST https://api.velt.dev/v1/organizations/documents/access/update

Use this API to update the access type for a single or multiple documents at once.

<Tip>
  You can update the default access type for all the documents associated with your API Key in [console](https://console.velt.dev/dashboard/config/appconfig).
</Tip>

# Endpoint

`https://api.velt.dev/v1/organizations/documents/access/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentIds" type="string[]" required>
      Array of Document IDs
    </ParamField>

    <ParamField body="accessType" type="string" default="public" required>
      Access type for the documents. Allowed values: `organizationPrivate`, `restricted`, `public`.
      [Learn more](/key-concepts/access-control/overview).
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentIds": ["yourDocumentId1, yourDocumentId2"],
    "accessType": "organizationPrivate"
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Updated access for documents successfully.",
    "data": {
      "yourDocumentId": {
        "success": true,
        "accessType": "organizationPrivate",
        "message": "Document access type updated."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Updated access for documents successfully.",
      "data": {
        "yourDocumentId": {
          "success": true,
          "accessType": "organizationPrivate",
          "message": "Document access type updated."
        }
      }
    }
  }
  ```
</ResponseExample>


# Update Disabled State for Documents

POST https://api.velt.dev/v1/organizations/documents/access/disablestate/update

Use this API to enable or disable both read and write access for all users.

<Info> Let's say your customer's trial or subscription has ended and you want to disable their access to the Velt data, you could use this to diable access to specific documents.</Info>

# Endpoint

`https://api.velt.dev/v1/organizations/documents/access/disablestate/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentIds" type="string[]" required>
      Array of Document IDs
    </ParamField>

    <ParamField body="disabled" type="boolean" default="false" required>
      Whether to disable read and write access to the specified documents. Allowed values: `true`, `false`
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentIds": ["yourDocumentId"],
    "disabled": true
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Updated disable state for documents successfully.",
    "data": {
      "yourDocumentId": {
        "success": true,
        "disabled": true,
        "message": "Document disabled state updated."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Updated disable state for documents successfully.",
      "data": {
        "yourDocumentId": {
          "success": true,
          "disabled": true,
          "message": "Document disabled state updated."
        }
      }
    }
  }
  ```
</ResponseExample>


# Update Documents

POST https://api.velt.dev/v1/organizations/documents/update

Use this API to update metadata of documents within an organization.

# Endpoint

`POST https://api.velt.dev/v1/organizations/documents/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documents" type="Document[]" required>
      Array of Document objects
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documents": [
      {
        "documentId": "yourDocumentId",
        "documentName": "Your Document Name"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Document(s) updated successfully.",
    "data": {
      "yourDocumentId": {
        "success": true,
        "id": "8121657101517513",
        "message": "Updated Successfully"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Document(s) updated successfully.",
      "data": {
        "yourDocumentId": {
          "success": true,
          "id": "8121657101517513",
          "message": "Updated Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Delete Data by Location

POST https://api.velt.dev/v1/organizations/documents/locations/data/delete
Delete all data associated with a specific location

Use this API to delete all data (comments, recordings, or any other feature data) associated with a specific location.

# Endpoint

`POST https://api.velt.dev/v1/organizations/documents/locations/data/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="apiKey" type="string" required>
      Your API key
    </ParamField>

    <ParamField body="authToken" type="string" required>
      Your Auth Token
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="location" type="object" required>
      The location object containing the data to be deleted
    </ParamField>
  </Expandable>
</ParamField>

## **Example Request**

```JSON
{
  "data": {
    "apiKey": "YOUR_API_KEY",
    "authToken": "YOUR_AUTH_TOKEN",
    "documentId": "YOUR_DOCUMENT_ID",
    "location": {
      "id": "scene_1",
      "locationName": "White scene"
    }
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Data deleted successfully.",
    "data": null
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Data deleted successfully.",
      "data": null
    }
  }
  ```
</ResponseExample>


# Update Location

POST https://api.velt.dev/v1/organizations/documents/locations/update
Update a Location's metadata

Use this API to update a Location's metadata.

# Endpoint

`POST https://api.velt.dev/v1/organizations/documents/locations/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="apiKey" type="string" required>
      Your API key
    </ParamField>

    <ParamField body="authToken" type="string" required>
      Your Auth Token
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="migrate" type="object" required>
      <Expandable title="properties">
        <ParamField body="oldLocation" type="object" required>
          The current location object
        </ParamField>

        <ParamField body="newLocation" type="object" required>
          The updated location object
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="merge" type="boolean">
      When true, merges new location fields with existing ones. When false, completely replaces the old location object.
      Default: false
    </ParamField>
  </Expandable>
</ParamField>

## **Example Request**

```JSON
{
  "data": {
    "apiKey": "YOUR_API_KEY",
    "authToken": "YOUR_AUTH_TOKEN",
    "documentId": "YOUR_DOCUMENT_ID",
    "migrate": {
      "oldLocation": {
        "id": "scene_1",
        "locationName": "Untitled scene"
      },
      "newLocation": {
        "id": "scene_1",
        "locationName": "White scene"
      }
    },
    "merge": true
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Location updated.",
    "data": null
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Location updated.",
      "data": null
    }
  }
  ```
</ResponseExample>


# Add Notifications

POST https://api.velt.dev/v1/notifications/add

Use this API to add notifications.

# Endpoint

`POST https://api.velt.dev/v1/notifications/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string" required>
      Document ID
    </ParamField>

    <ParamField body="actionUser" type="User" required>
      User who took the action
    </ParamField>

    <ParamField body="displayHeadlineMessageTemplate" type="string" required>
      Display Headline Message Template
    </ParamField>

    <ParamField body="displayHeadlineMessageTemplateData" type="object">
      Display Headline Message Template Data (Optional)

      <Expandable title="properties">
        <ParamField body="actionUser" type="User">
          User who took the action
        </ParamField>

        <ParamField body="recipientUser" type="string">
          User who was directly affected by the action
        </ParamField>

        <ParamField body="yourCustomField" type="string">
          Any custom field with string value
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="displayBodyMessage" type="string" required>
      Display Body Message
    </ParamField>

    <ParamField body="notifyUsers" type="User[]" required>
      Array of Notify Users
    </ParamField>

    <ParamField body="notificationSourceData" type="object">
      Any custom object to be stored with the notification.
      When the user clicks on the notification, this data will be sent in the callback.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Request**

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "actionUser": {
      "userId": "yourUserId",
      "name": "User Name",
      "email": "user@example.com"
    },
    "displayHeadlineMessageTemplate": "This is main template, you can pass variables using curly brackets like this: {actionUser}, {recipientUser}, {yourCustomVariableWithStringValue}",
    "displayHeadlineMessageTemplateData": {
      "actionUser": {
        "userId": "yourUserId",
        "name": "User Name",
        "email": "user@example.com"
      },
      "recipientUser": {
        "userId": "recipientUserId",
        "name": "Recipient Name",
        "email": "recipient@example.com"
      },
      "yourCustomField": "Variable will be replaced with this text"
    },
    "displayBodyMessage": "This is body message (Secondary message)",
    "notifyUsers": [
      {
        "email": "test@example.com",
        "userId": "testingUserId"
      },
      {
        "userId": "yourUserId",
        "name": "User Name",
        "email": "user@example.com"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Notification added successfully.",
    "data": {
      "success": true,
      "message": "Notification added successfully."
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Notification added successfully.",
      "data": {
        "success": true,
        "message": "Notification added successfully."
      }
    }
  }
  ```
</ResponseExample>


# Delete Notifications

POST https://api.velt.dev/v1/notifications/delete

Use this API to delete notifications.

# Endpoint

`POST https://api.velt.dev/v1/notifications/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document ID (Optional)
    </ParamField>

    <ParamField body="locationId" type="string">
      Location ID (Optional)
    </ParamField>

    <ParamField body="userId" type="string">
      User ID (Optional)
    </ParamField>

    <ParamField body="notificationIds" type="string[]">
      Array of Notification IDs (Optional)
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Delete by organizationId and documentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId"
  }
}
```

#### 2. Delete by organizationId, documentId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 3. Delete by organizationId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId"
  }
}
```

#### 4. Delete by organizationId, userId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 5. Delete by organizationId, documentId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userId": "yourUserId"
  }
}
```

#### 6. Delete by organizationId, documentId, userId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userId": "yourUserId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 7.Delete by organizationId, documentId and locationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationId": "yourLocationId"
  }
}
```

#### 8. Delete by organizationId, documentId, locationId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationId": "yourLocationId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 9. Delete by organizationId, locationId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "locationId": "yourLocationId",
    "userId": "yourUserId",
  }
}
```

#### 10. Delete by organizationId, locationId, userId, and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "locationId": "yourLocationId",
    "userId": "yourUserId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 11. Delete by organizationId, documentId, locationId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationId": "yourLocationId",
    "userId": "yourUserId",
  }
}
```

# Response

#### Success Response

```JSON
{
   "result": {
       "status": "success",
       "message": "Notification(s) deleted successfully.",
       "data": {
           "8955243231506071": {
               "success": true,
               "message": "Notification deleted."
           }
       }
   }
}
```

#### When some notifications are not found

```JSON
{
   "result": {
       "status": "success",
       "message": "Notification(s) deleted successfully.",
       "data": {
           "89552432315060712": {
               "success": false,
               "message": "Failed to delete notification."
           },
           "8955243231506071": {
               "success": true,
               "message": "Notification deleted."
           }
       }
   }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
     "result": {
         "status": "success",
         "message": "Notification(s) deleted successfully.",
         "data": {
             "8955243231506071": {
                 "success": true,
                 "message": "Notification deleted."
             }
         }
     }
  }
  ```
</ResponseExample>


# Get Notifications

POST https://api.velt.dev/v1/notifications/get

Use this API to retrieve notifications.

# Endpoint

`POST https://api.velt.dev/v1/notifications/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document ID
    </ParamField>

    <ParamField body="locationId" type="string">
      Location ID
    </ParamField>

    <ParamField body="userId" type="string">
      User ID
    </ParamField>

    <ParamField body="notificationIds" type="string[]">
      Array of Notification IDs. Limit: Only 30 items can be passed at a time.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get by organizationId, documentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId"
  }
}
```

#### 2. Get by organizationId, documentId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 3. Get by organizationId, documentId and locationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationId": "yourLocationId"
  }
}
```

#### 4. Get by organizationId, documentId, locationId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationId": "yourLocationId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 5. Get by organizationId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId"
  }
}
```

#### 6. Get by organizationId, userId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 7. Get by organizationId, documentId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userId": "yourUserId"
  }
}
```

#### 8. Get by organizationId, locationId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId",
    "locationId": "yourLocationId"
  }
}
```

#### 9. Get by organizationId, documentId, locationId, and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userId": "yourUserId",
    "locationId": "yourLocationId"
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Notification(s) retrieved successfully.",
    "data": [
      {
        "id": "notificationId",
        "notificationSource": "custom",
        "notificationSourceData": {}, //The data of the notification source. e.g., CommentAnnotation
        "actionUser": {
          "email": "user@example.com",
          "name": "User Name",
          "userId": "yourUserId"
        },
        "displayBodyMessage": "This is body message (Secondary message)",
        "displayHeadlineMessageTemplate": "This is main template, you can pass variables using curly brackets like this: {actionUser}, {recipientUser}, {yourCustomVariableWithStringValue}",
        "displayHeadlineMessageTemplateData": {
          "actionUser": {
            "email": "user@example.com",
            "name": "User Name",
            "userId": "yourUserId"
          },
          "recipientUser": {
            "email": "recipient@example.com",
            "name": "Recipient Name",
            "userId": "recipientUserId"
          },
          "yourCustomVariableWithStringValue": "Variable will be replaced with this text"
        },
        "metadata": {
          "apiKey": "yourApiKey",
          "documentId": "yourDocumentId",
          "organizationId": "yourOrganizationId"
        },
        "notifyUsers": {
          "yourNotifyUserId": true
        },
        "notifyUsersByUserId": {
          "yourNotifyUserById": true
        },
        "timestamp": 1722409519944
      }
    ]
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Notification(s) retrieved successfully.",
      "data": [
        {
          "id": "notificationId",
          "notificationSource": "custom",
          "notificationSourceData": {}, //The data of the notification source. e.g., CommentAnnotation
          "actionUser": {
            "email": "user@example.com",
            "name": "User Name",
            "userId": "yourUserId"
          },
          "displayBodyMessage": "This is body message (Secondary message)",
          "displayHeadlineMessageTemplate": "This is main template, you can pass variables using curly brackets like this: {actionUser}, {recipientUser}, {yourCustomVariableWithStringValue}",
          "displayHeadlineMessageTemplateData": {
            "actionUser": {
              "email": "user@example.com",
              "name": "User Name",
              "userId": "yourUserId"
            },
            "recipientUser": {
              "email": "recipient@example.com",
              "name": "Recipient Name",
              "userId": "recipientUserId"
            },
            "yourCustomVariableWithStringValue": "Variable will be replaced with this text"
          },
          "metadata": {
            "apiKey": "yourApiKey",
            "documentId": "yourDocumentId",
            "organizationId": "yourOrganizationId"
          },
          "notifyUsers": {
            "yourNotifyUserId": true
          },
          "notifyUsersByUserId": {
            "yourNotifyUserById": true
          },
          "timestamp": 1722409519944
        }
      ]
    }
  }
  ```
</ResponseExample>


# Get Notifications v2

POST https://api.velt.dev/v2/notifications/get

Use this API to retrieve notifications.

# Endpoint

`POST https://api.velt.dev/v2/notifications/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document ID. Either pass this or userId.
    </ParamField>

    <ParamField body="locationId" type="string">
      Location ID
    </ParamField>

    <ParamField body="userId" type="string">
      User ID. Either pass this or documentId.
    </ParamField>

    <ParamField body="notificationIds" type="string[]">
      Array of Notification IDs. Limit: Only 30 items can be passed at a time.
    </ParamField>

    <ParamField body="pageSize" type="number">
      Number of items to be retrieved per page. Default: 1000.
    </ParamField>

    <ParamField body="pageToken" type="string">
      Page token retrieved from previous API call.
    </ParamField>

    <ParamField body="order" type="'asc' | 'desc'">
      Order of the notifications based on timestamp. Default: desc.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get by organizationId, documentId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "pageSize": 20,
    "pageToken": "8740648311207869"
  }
}
```

#### 2. Get by organizationId, documentId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 3. Get by organizationId, documentId and locationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationId": "yourLocationId",
    "pageSize": 20,
    "pageToken": "8740648311207869"
  }
}
```

#### 4. Get by organizationId, documentId, locationId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "locationId": "yourLocationId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 5. Get by organizationId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId",
    "pageSize": 20,
    "pageToken": "8740648311207869"
  }
}
```

#### 6. Get by organizationId, userId and notificationIds

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId",
    "notificationIds": [
      "yourNotificationId"
    ]
  }
}
```

#### 7. Get by organizationId, documentId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userId": "yourUserId",
    "pageSize": 20,
    "pageToken": "8740648311207869"
  }
}
```

#### 8. Get by organizationId, locationId and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userId": "yourUserId",
    "locationId": "yourLocationId",
    "pageSize": 20,
    "pageToken": "8740648311207869"
  }
}
```

#### 9. Get by organizationId, documentId, locationId, and userId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userId": "yourUserId",
    "locationId": "yourLocationId",
    "pageSize": 20,
    "pageToken": "8740648311207869"
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Notification(s) retrieved successfully.",
    "data": [
      {
        "id": "notificationId",
        "notificationSource": "custom",
        "notificationSourceData": {}, //The data of the notification source. e.g., CommentAnnotation
        "actionUser": {
          "email": "user@example.com",
          "name": "User Name",
          "userId": "yourUserId"
        },
        "displayBodyMessage": "This is body message (Secondary message)",
        "displayHeadlineMessageTemplate": "This is main template, you can pass variables using curly brackets like this: {actionUser}, {recipientUser}, {yourCustomVariableWithStringValue}",
        "displayHeadlineMessageTemplateData": {
          "actionUser": {
            "email": "user@example.com",
            "name": "User Name",
            "userId": "yourUserId"
          },
          "recipientUser": {
            "email": "recipient@example.com",
            "name": "Recipient Name",
            "userId": "recipientUserId"
          },
          "yourCustomVariableWithStringValue": "Variable will be replaced with this text"
        },
        "metadata": {
          "apiKey": "yourApiKey",
          "documentId": "yourDocumentId",
          "organizationId": "yourOrganizationId"
        },
        "notifyUsers": {
          "yourNotifyUserId": true
        },
        "notifyUsersByUserId": {
          "yourNotifyUserById": true
        },
        "timestamp": 1722409519944
      }
    ],
    "pageToken": "nextPageToken"
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Notification(s) retrieved successfully.",
      "data": [
        {
          "id": "notificationId",
          "notificationSource": "custom",
          "notificationSourceData": {}, //The data of the notification source. e.g., CommentAnnotation
          "actionUser": {
            "email": "user@example.com",
            "name": "User Name",
            "userId": "yourUserId"
          },
          "displayBodyMessage": "This is body message (Secondary message)",
          "displayHeadlineMessageTemplate": "This is main template, you can pass variables using curly brackets like this: {actionUser}, {recipientUser}, {yourCustomVariableWithStringValue}",
          "displayHeadlineMessageTemplateData": {
            "actionUser": {
              "email": "user@example.com",
              "name": "User Name",
              "userId": "yourUserId"
            },
            "recipientUser": {
              "email": "recipient@example.com",
              "name": "Recipient Name",
              "userId": "recipientUserId"
            },
            "yourCustomVariableWithStringValue": "Variable will be replaced with this text"
          },
          "metadata": {
            "apiKey": "yourApiKey",
            "documentId": "yourDocumentId",
            "organizationId": "yourOrganizationId"
          },
          "notifyUsers": {
            "yourNotifyUserId": true
          },
          "notifyUsersByUserId": {
            "yourNotifyUserById": true
          },
          "timestamp": 1722409519944
        }
      ],
      "pageToken": "nextPageToken"
    }
  }
  ```
</ResponseExample>


# Update Notifications

POST https://api.velt.dev/v1/notifications/update

Use this API to update notifications.

# Endpoint

`POST https://api.velt.dev/v1/notifications/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document ID (Optional)
    </ParamField>

    <ParamField body="locationId" type="string">
      Location ID
    </ParamField>

    <ParamField body="userId" type="string">
      User ID  (Optional)
    </ParamField>

    <ParamField body="notifications" type="object">
      Notifications object

      <Expandable title="properties">
        <ParamField body="id" type="string">
          Notification ID
        </ParamField>

        <ParamField body="actionUser" type="User">
          User who took the action
        </ParamField>

        <ParamField body="displayHeadlineMessageTemplate" type="string">
          Display Headline Message Template
        </ParamField>

        <ParamField body="displayHeadlineMessageTemplateData" type="object">
          Display Headline Message Template Data

          <Expandable title="properties">
            <ParamField body="actionUser" type="User">
              User who took the action
            </ParamField>

            <ParamField body="recipientUser" type="string">
              User who was directly affected by the action
            </ParamField>

            <ParamField body="yourCustomField" type="string">
              Any custom field with string value
            </ParamField>
          </Expandable>
        </ParamField>

        <ParamField body="displayBodyMessage" type="string">
          Display Body Message
        </ParamField>

        <ParamField body="notificationSourceData" type="object">
          Any custom object to be stored with the notification.
          When the user clicks on the notification, this data will be sent to in the callback.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Update by organizationId and documentId

```JSON
{
   "data": {
       "organizationId": "yourOrganizationId",
       "documentId": "yourDocumentId",
       "notifications": [
           {
               "id": "yourNotificationId",
               "displayBodyMessage": "This is body message (Secondary message)",
           }
       ]
   }
}
```

#### 2. Update by organizationId, documentId and locationId

```JSON
{
   "data": {
       "organizationId": "yourOrganizationId",
       "documentId": "yourDocumentId",
       "locationId": "yourLocationId",
       "notifications": [
           {
               "id": "yourNotificationId",
               "displayBodyMessage": "This is body message (Secondary message)",
           }
       ]
   }
}
```

#### 3. Update by organizationId, documentId and userId

```JSON
{
   "data": {
       "organizationId": "yourOrganizationId",
       "documentId": "yourDocumentId",
       "userId": "yourUserId",
       "notifications": [
           {
               "id": "yourNotificationId",
               "displayBodyMessage": "This is body message (Secondary message)",
           }
       ]
   }
}
```

#### 4. Update by organizationId and userId

```JSON
{
   "data": {
       "organizationId": "yourOrganizationId",
       "userId": "yourUserId",
       "notifications": [
           {
               "id": "yourNotificationId",
               "displayBodyMessage": "This is body message (Secondary message)",
           }
       ]
   }
}
```

#### 5. Update by organizationId, documentId, locationId and userId

```JSON
{
   "data": {
       "organizationId": "yourOrganizationId",
       "documentId": "yourDocumentId",
       "userId": "yourUserId",
       "locationId": "yourLocationId",
       "notifications": [
           {
               "id": "yourNotificationId",
               "displayBodyMessage": "This is body message (Secondary message)",
           }
       ]
   }
}
```

# Response

#### Success Response

```JSON
{
   "result": {
       "status": "success",
       "message": "Notification(s) updated successfully.",
       "data": {
           "5471488637912692": {
               "success": true,
               "message": "Notification updated."
           }
       }
   }
}
```

#### When some notifications are not found

```JSON
{
   "result": {
       "status": "success",
       "message": "Notification(s) updated successfully.",
       "data": {
           "5471488637912692": {
               "success": false,
               "message": "Failed to update notification."
           },
           "5471488637912693": {
               "success": true,
               "message": "Notification updated."
           }
       }
   }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
     "result": {
         "status": "success",
         "message": "Notification(s) updated successfully.",
         "data": {
             "5471488637912692": {
                 "success": true,
                 "message": "Notification updated."
             }
         }
     }
  }
  ```
</ResponseExample>


# Add User Groups

POST https://api.velt.dev/v1/organizations/usergroups/add

Use this API to add organization user groups to a specific organization.

# Endpoint

`POST https://api.velt.dev/v1/organizations/usergroups/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="organizationUserGroups" type="OrganizationUserGroup[]" required>
      Array of Organization User Group objects
    </ParamField>
  </Expandable>
</ParamField>

## **Example Request**

#### Add organization user group in a specific organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "organizationUserGroups": [
      {
        "groupId": "engineering",
        "groupName": "Engineering"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Organization User Groups added successfully.",
    "data": {
      "yourGroupId": {
        "success": true,
        "id": "77ab6767b022ad0323ba39c24f12cc95",
        "message": "Organization user group added."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Organization User Groups added successfully.",
      "data": {
        "yourGroupId": {
          "success": true,
          "id": "77ab6767b022ad0323ba39c24f12cc95",
          "message": "Organization user group added."
        }
      }
    }
  }
  ```
</ResponseExample>


# Add Users to Groups

POST https://api.velt.dev/v1/organizations/usergroups/users/add

Use this API to add users to a specific organization user group.

# Endpoint

`POST https://api.velt.dev/v1/organizations/usergroups/users/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="organizationUserGroupId" type="string" required>
      Organization User Group ID
    </ParamField>

    <ParamField body="userIds" type="string[]" required>
      Array of User IDs
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "organizationUserGroupId": "yourGroupId",
    "userIds": ["yourUserId1"]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Added organization users to group successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "organizationUserGroupId": "yourGroupId",
        "message": "User added to organization user group."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Added organization users to group successfully.",
      "data": {
        "yourUserId1": {
          "success": true,
          "organizationUserGroupId": "yourGroupId",
          "message": "User added to organization user group."
        }
      }
    }
  }
  ```
</ResponseExample>


# Delete Users from Groups

POST https://api.velt.dev/v1/organizations/usergroups/users/delete

Use this API to delete users from a specific organization user group.

# Endpoint

`POST https://api.velt.dev/v1/organizations/usergroups/users/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="organizationUserGroupId" type="string" required>
      Organization User Group ID
    </ParamField>

    <ParamField body="userIds" type="string[]" required>
      Array of User IDs
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### Delete specific users from group

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "organizationUserGroupId": "yourGroupId",
    "userIds": ["yourUserId1"]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Deleted users from group successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "organizationUserGroupId": "yourGroupId",
        "message": "User deleted from organization user group."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Deleted users from group successfully.",
      "data": {
        "yourUserId1": {
          "success": true,
          "organizationUserGroupId": "yourGroupId",
          "message": "User deleted from organization user group."
        }
      }
    }
  }
  ```
</ResponseExample>


# Add Organizations

POST https://api.velt.dev/v1/organizations/add

Use this API to add new organizations and its metadata.

# Endpoint

`POST https://api.velt.dev/v1/organizations/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizations" type="Organization[]" required>
      Array of Organization objects
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### Add organization

```JSON
{
  "data": {
    "organizations": [
      {
        "organizationId": "yourOrganizationId",
        "organizationName": "Your Organization Name"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Organization(s) added successfully.",
    "data": {
      "yourOrganizationId": {
        "success": true,
        "id": "02cf91e5e7a5f4c0b600c84cf248384b",
        "message": "Added Successfully"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Organization(s) added successfully.",
      "data": {
        "yourOrganizationId": {
          "success": true,
          "id": "02cf91e5e7a5f4c0b600c84cf248384b",
          "message": "Added Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Delete Organizations

POST https://api.velt.dev/v1/organizations/delete

Use this API to delete specific organization(s) data by their IDs.

# Endpoint

`POST https://api.velt.dev/v1/organizations/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationIds" type="string[]" required>
      Array of Organization IDs
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### Delete specific organization

```JSON
{
  "data": {
    "organizationIds": [
      "yourOrganizationId1",
      "yourOrganizationId2"
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Organization(s) deleted successfully.",
    "data": {
      "yourOrganizationId1": {
        "success": true,
        "id": "02cf91e5e7a5f4c0b600c84cf248384b",
        "message": "Deleted Successfully"
      },
      {
      "yourOrganizationId2": {
        "success": false,
        "id": "02cf91e5e7a5f4c0b600c84cf248384b",
        "message": "Organization does not exist"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Organization(s) deleted successfully.",
      "data": {
        "yourOrganizationId": {
          "success": true,
          "id": "02cf91e5e7a5f4c0b600c84cf248384b",
          "message": "Deleted Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Get Organizations

POST https://api.velt.dev/v1/organizations/get

Use this API to retrieve specific organizations by organization IDs.

# Endpoint

`POST https://api.velt.dev/v1/organizations/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationIds" type="string[]">
      Array of Organization IDs (Optional).
      Limit: Only 30 IDs can be passed at a time.
      If this is not provided, all organizations will be returned.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationIds": [
      "yourOrganizationId"
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Organization(s) retrieved successfully.",
    "data": [
      {
        "id": "yourOrganizationId",
        "organizationName": "Your Organization Name",
        "disabled": false,
        // other metadata fields may be included here
      }
      // ... more organizations if multiple were retrieved
    ]
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Organization(s) retrieved successfully.",
      "data": [
        {
          "id": "yourOrganizationId",
          "organizationName": "Your Organization Name",
          "disabled": false,
          // other metadata fields may be included here
        }
        // ... more organizations if multiple were retrieved
      ]
    }
  }
  ```
</ResponseExample>


# Get Organizations v2

POST https://api.velt.dev/v2/organizations/get

Use this API to retrieve specific organizations by organization IDs.

# Endpoint

`POST https://api.velt.dev/v2/organizations/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationIds" type="string[]">
      Array of Organization IDs (Optional).
      Limit: Only 30 IDs can be passed at a time.
      If this is not provided, all organizations will be returned.
    </ParamField>

    <ParamField body="pageSize" type="number">
      Number of items to be retrieved per page (Optional). Default: 1000.
    </ParamField>

    <ParamField body="pageToken" type="string">
      Page token retrieved from previous API call. (Optional)
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationIds": [
      "yourOrganizationId"
    ],
    "pageSize": 1000,
    "pageToken": "pageToken"
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Organization(s) retrieved successfully.",
    "data": [
      {
        "id": "yourOrganizationId",
        "organizationName": "Your Organization Name",
        "disabled": false,
        // other metadata fields may be included here
      }
      // ... more organizations if multiple were retrieved
    ],
    "nextPageToken": "pageToken"
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Organization(s) retrieved successfully.",
      "data": [
        {
          "id": "yourOrganizationId",
          "organizationName": "Your Organization Name",
          "disabled": false,
          // other metadata fields may be included here
        }
        // ... more organizations if multiple were retrieved
      ],
      "nextPageToken": "pageToken"
    }
  }
  ```
</ResponseExample>


# Update Disabled State for Organizations

POST https://api.velt.dev/v1/organizations/access/disablestate/update

Use this API to enable or disable both read and write access for all documents for all users.

<Info> Let's say your customer's trial or subscription has ended and you want to disable their access to the Velt data, you could use this to disable access to the entire organization data.</Info>
<Info>If organization does not exist, it will be created.</Info>

# Endpoint

`POST https://api.velt.dev/v1/organizations/access/disablestate/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationIds" type="string[]" required>
      Array of Organization IDs
    </ParamField>

    <ParamField body="disabled" type="boolean" required>
      Whether to disable read and write access to the specified organizations. Allowed values: `true`, `false`.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizationIds": ["yourOrganizationId1","yourOrganizationId2"],
    "disabled": true
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Updated disable state for Organization(s) successfully.",
    "data": {
      "yourOrganizationId1": {
        "success": true,
        "id": "02cf91e5e7a5f4c0b600c84cf248384b",
        "message": "Updated disable state for organization Successfully"
      },
      "yourOrganizationId2": {
        "success": false,
        "id": "44e0132f4c6b0d453f18df42d2263b4e",
        "message": "Organization does not exist"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Updated disable state for Organization(s) successfully.",
      "data": {
        "yourOrganizationId": {
          "success": true,
          "id": "02cf91e5e7a5f4c0b600c84cf248384b",
          "message": "Updated disable state for organization Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Update Organizations

POST https://api.velt.dev/v1/organizations/update

Use this API to update existing organization(s) metadata.

# Endpoint

`POST https://api.velt.dev/v1/organizations/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizations" type="Organization[]" required>
      Array of Organization objects
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

```JSON
{
  "data": {
    "organizations": [
      {
        "organizationId": "yourOrganizationId",
        "organizationName": "Your Updated Organization Name"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "Organization(s) updated successfully.",
    "data": {
      "yourOrganizationId": {
        "success": true,
        "id": "02cf91e5e7a5f4c0b600c84cf248384b",
        "message": "Updated Successfully"
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Organization(s) updated successfully.",
      "data": {
        "yourOrganizationId": {
          "success": true,
          "id": "02cf91e5e7a5f4c0b600c84cf248384b",
          "message": "Updated Successfully"
        }
      }
    }
  }
  ```
</ResponseExample>


# Add Users

POST https://api.velt.dev/v1/users/add

Use this API to add Users to:

1.  **Organization:** This will provide them access to all the documents in the organization. It will also show users in the contact list of the organization.
2.  **Document:** This will provide them access to the specified document. It will also show users in the contact list of the document. If you pass the `documentId`, then the users will be added to the document.

<Info>If organization does not exist, it will be created. </Info>

<Info>If User's `initial` is not provided in the User object, then it will be automatically created using the name field. </Info>

# Endpoint

`POST https://api.velt.dev/v1/users/add`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document IDs. Provide this if you want to add users to a specific document.
    </ParamField>

    <ParamField body="users" type="User[]" required>
      Array of [User](/api-reference/models/User) objects.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Add users to a specific organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "users": [
      {
        "userId": "yourUserId1",
        "name": "User Name",
        "email": "user@email.com"
      }
    ]
  }
}
```

#### 2. Add users to a specific document within an organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "users": [
      {
        "userId": "yourUserId1",
        "name": "User Name",
        "email": "user@email.com"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) processed successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "id": "4c250058149d6c9fb8c894c9ef29c790",
        "message": "User added."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "User(s) processed successfully.",
      "data": {
        "yourUserId1": {
          "success": true,
          "id": "4c250058149d6c9fb8c894c9ef29c790",
          "message": "User added."
        }
      }
    }
  }
  ```
</ResponseExample>


# Delete All User Data (GDPR)

POST https://api.velt.dev/v1/users/data/delete
Remove All User data from Velt.

Use this API to remove all user data from Velt. This will:

*   remove their access from all the documents and data in the organization.
*   remove them from @mention contact dropdown list.
*   remove them from @mentions where they were tagged.
*   remove all feature data created by the user. eg: comments, reactions, notifications etc.

# Endpoint

`POST https://api.velt.dev/v1/users/data/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="userIds" type="string[]" required>
      Array of user Ids.
    </ParamField>

    <ParamField body="organizationIds" type="string[]">
      Array of organization Ids. These are the organizations that the user is part of.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Request**

```JSON
{
  "data": {
    "userIds": [
      "yourUserId1",
      "yourUserId2"
    ],
    "organizationIds": [
      "yourOrganizationId1",
      "yourOrganizationId2"
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) deleted successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "message": "User removed."
      }
    }
  }
}
```

#### User(s) Not Found

```JSON
{
  "result": {
    "status": "success",
    "message": "Deleted user data successfully.",
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "Deleted user data successfully.",
    }
  }
  ```
</ResponseExample>


# Delete Users

POST https://api.velt.dev/v1/users/delete
Remove Users from an Organization or a Document.

Use this API to remove Users from:

1.  **Organization:** This will remove their access from all the documents and data in the organization. It will also remove these users from the contact list of the organization.
2.  **Document:** This will remove their access from the specified document. It will also remove these users from the contact list of the document. If you pass the `documentId`, then the users will be removed from the document.

# Endpoint

`POST https://api.velt.dev/v1/users/delete`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### Params

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document IDs. Provide this if you want to delete users from a specific document.
    </ParamField>

    <ParamField body="userIds" type="string[]" required>
      Array of user Ids.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Delete users in a specific organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userIds": [
      "yourUserId1"
    ]
  }
}
```

#### 2. Delete users in a specific document within an organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId1"
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) deleted successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "message": "User removed."
      }
    }
  }
}
```

#### User(s) Not Found

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) deleted successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "message": "User removed."
      },
      {
      "yourUserId2": {
        "success": false,
        "message": "User does not exist."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "User(s) deleted successfully.",
      "data": {
        "yourUserId1": {
          "success": true,
          "message": "User removed."
        }
      }
    }
  }
  ```
</ResponseExample>


# Get Users

POST https://api.velt.dev/v1/users/get

Use this API to retrieve users based on various filters such as organization ID, document ID, organization user group IDs or user IDs. You can use these filters in various combinations to get the desired users. Some examples are shown below.

# Endpoint

`POST https://api.velt.dev/v1/users/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### **Params**

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document ID
    </ParamField>

    <ParamField body="userIds" type="string[]">
      Array of User IDs. Limit: Only 30 items can be passed at a time.
    </ParamField>

    <ParamField body="organizationUserGroupIds" type="string[]">
      Array of Organization User Group IDs. Only 30 items can be passed at a time.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get users by organizationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId"
  }
}
```

#### 2. Get users by documentId within an organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId"
  }
}
```

#### 3. Get users by specific user IDs in an organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userIds": [
      "yourUserId1",
      "yourUserId2"
    ]
  }
}
```

#### 4. Get users by specific user IDs in the given organization and document

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId1",
      "yourUserId2"
    ]
  }
}
```

#### 5. Get users by organization and organization user group IDs

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "organizationUserGroupIds": [
      "yourOrganizationUserGroupId"
    ]
  }
}
```

#### 6. Get users by organization, organization user group IDs and user IDs

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userIds": [
      "yourUserId1",
      "yourUserId2"
    ],
    "organizationUserGroupIds": [
      "yourOrganizationUserGroupId"
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) retrieved successfully.",
    "data": [
      {
        "email": "userEmail@domain.com",
        "name": "userName",
        "userId": "yourUserId"
      }
    ]
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "Error retrieving user(s).",
    "status": "ERROR_CODE"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "User(s) retrieved successfully.",
      "data": [
        {
          "email": "userEmail@domain.com",
          "name": "userName",
          "userId": "yourUserId"
        }
      ]
    }
  }
  ```
</ResponseExample>


# Get Users v2

POST https://api.velt.dev/v2/users/get

Use this API to retrieve users based on various filters such as organization ID, document ID, organization user group IDs or user IDs. You can use these filters in various combinations to get the desired users. Some examples are shown below.

# Endpoint

`POST https://api.velt.dev/v2/users/get`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### **Params**

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document ID
    </ParamField>

    <ParamField body="userIds" type="string[]">
      Array of User IDs. Limit: Only 30 items can be passed at a time.
    </ParamField>

    <ParamField body="organizationUserGroupIds" type="string[]">
      Array of Organization User Group IDs. Only 30 items can be passed at a time.
    </ParamField>

    <ParamField body="pageSize" type="number">
      Number of items to be retrieved per page. Default: 1000.
    </ParamField>

    <ParamField body="pageToken" type="string">
      Page token retrieved from previous API call.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Get users by organizationId

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "pageSize": 1000,
    "pageToken": "pageToken"
  }
}
```

#### 2. Get users by documentId within an organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId"
  }
}
```

#### 3. Get users by specific user IDs in an organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userIds": [
      "yourUserId1",
      "yourUserId2"
    ]
  }
}
```

#### 4. Get users by specific user IDs in the given organization and document

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "userIds": [
      "yourUserId1",
      "yourUserId2"
    ]
  }
}
```

#### 5. Get users by organization and organization user group IDs

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "organizationUserGroupIds": [
      "yourOrganizationUserGroupId"
    ]
  }
}
```

#### 6. Get users by organization, organization user group IDs and user IDs

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "userIds": [
      "yourUserId1",
      "yourUserId2"
    ],
    "organizationUserGroupIds": [
      "yourOrganizationUserGroupId"
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) retrieved successfully.",
    "data": [
      {
        "email": "userEmail@domain.com",
        "name": "userName",
        "userId": "yourUserId"
      }
    ],
    "pageToken": "pageToken"
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "Error retrieving user(s).",
    "status": "ERROR_CODE"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "User(s) retrieved successfully.",
      "data": [
        {
          "email": "userEmail@domain.com",
          "name": "userName",
          "userId": "yourUserId"
        }
      ],
      "pageToken": "pageToken"
    }
  }
  ```
</ResponseExample>


# Update Users

POST https://api.velt.dev/v1/users/update

Use this API to update user metadata based on various filters such as organization ID, document ID, and user IDs.
You can use these filters in various combinations to get the desired results.
The user metadata such as name, email etc can be updated.

# Endpoint

`POST https://api.velt.dev/v1/users/update`

# Headers

<ParamField header="x-velt-api-key" type="string" required>
  Your API key.
</ParamField>

<ParamField header="x-velt-auth-token" type="string" required>
  Your [Auth Token](/security/auth-tokens).
</ParamField>

# Body Example

#### **Params**

<ParamField body="data" type="object" required>
  <Expandable title="properties">
    <ParamField body="organizationId" type="string" required>
      Organization ID
    </ParamField>

    <ParamField body="documentId" type="string">
      Document ID (Optional)
    </ParamField>

    <ParamField body="users" type="User[]" required>
      Array of [User](/api-reference/models/User) objects.
    </ParamField>
  </Expandable>
</ParamField>

## **Example Requests**

#### 1. Update users in a specific organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "users": [
      {
        "userId": "yourUserId1",
        "name": "User Name",
        "email": "user@email.com"
      }
    ]
  }
}
```

#### 2. Update users in a specific document within an organization

```JSON
{
  "data": {
    "organizationId": "yourOrganizationId",
    "documentId": "yourDocumentId",
    "users": [
      {
        "userId": "yourUserId1",
        "name": "User Name",
        "email": "user@email.com"
      }
    ]
  }
}
```

# Response

#### Success Response

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) processed successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "id": "7d87015b055a168b098cf05b870e40ff",
        "message": "User updated."
      }
    }
  }
}
```

#### Some User(s) Not Found

```JSON
{
  "result": {
    "status": "success",
    "message": "User(s) processed successfully.",
    "data": {
      "yourUserId1": {
        "success": true,
        "id": "7d87015b055a168b098cf05b870e40ff",
        "message": "User updated."
      },
      "yourUserId2": {
        "success": false,
        "id": "ad22d93b49ad990d2b3d582d08d7768a",
        "message": "User does not exist."
      }
    }
  }
}
```

#### Failure Response

```JSON
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "INVALID_ARGUMENT"
  }
}
```

<ResponseExample>
  ```js
  {
    "result": {
      "status": "success",
      "message": "User(s) processed successfully.",
      "data": {
        "yourUserId1": {
          "success": true,
          "id": "7d87015b055a168b098cf05b870e40ff",
          "message": "User updated."
        }
      }
    }
  }
  ```
</ResponseExample>


# Customize Behavior



## 1. Getting the Arrow Element

To get access to the Arrow Element APIs, you will first need to get the Arrow Element object from the client.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const arrowElement = client.getArrowElement();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const arrowElement = Velt.getArrowElement();
    ```
  </Tab>
</Tabs>

## 2. Set which elements Arrows can be added to

You can use the `allowedElementIds()` property to set an allowed list of elements the `Arrows` feature can be added to.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltArrows allowedElementIds={['ALLOWED_ID_1', 'ALLOWED_ID_2']} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-arrows allowed-element-ids="['ALLOWED_ID_1', 'ALLOWED_ID_2']"></velt-arrows>
    ```
  </Tab>
</Tabs>

API Methods:

You can use the `arrowElement.allowedElementIds()` method to set an allowed list of elements the `Arrows` feature can be added to.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    arrowElement.allowedElementIds(['ALLOWED_ID_1', 'ALLOWED_ID_2']);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    arrowElement.allowedElementIds(['ALLOWED_ID_1', 'ALLOWED_ID_2']);
    ```
  </Tab>
</Tabs>

## 3. Dark Mode

Whether dark mode is enabled.

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltArrows darkMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-arrows dark-mode="true"></velt-arrows>
    ```
  </Tab>
</Tabs>


# Arrows



<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=arrows" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=arrows)


# Setup



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import the Arrow components from @veltdev/react">
        Import the `Arrow` components

        ```js
        import { VeltArrows, VeltArrowTool } from '@veltdev/react';
        ```
      </Step>

      <Step title="Place the VeltArrows component">
        Place the `VeltArrows` component at the root of your app.

        ```js
        <div>
          <VeltArrows/>
        </div>
        ```
      </Step>

      <Step title="Place the VeltArrowTool component">
        Place the `VeltArrowsTool` component wherever you want the invite button to appear.

        ```js
        <div className="toolbar">
          <VeltArrowTool />
        </div>
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Place the <velt-arrows> component">
        Place the `<velt-arrows>` component at the root of your app.

        ```html
        <div>
          <velt-arrows></velt-arrows>
        </div>
        ```
      </Step>

      <Step title="Place the <velt-arrow-tool> component">
        Place the component wherever you want the invite button to appear.

        ```html
        <div class="toolbar">
          <velt-arrow-tool></velt-arrow-tool>
        </div>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { VeltArrows, VeltArrowTool } from '@veltdev/react';

  function YourComponent() {

    return (
      <div>
        <VeltArrows/>
        <div className="toolbar">
          <VeltArrowTool />
        </div>
        
      </div>
    )
    
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");
        }
      </script>
    </head>
    <body>
      <velt-arrows></velt-arrows>
      <div class="toolbar">
        <velt-arrow-tool></velt-arrow-tool>
      </div>
      
    </body>
  </html>
  ```
</RequestExample>


# Customize Behavior



## 1. Comment click event

*   Listen for click events on comments in the sidebar to trigger actions like navigation.
*   The event callback provides access to the clicked comment's annotation object, which includes `location` and `context` data.
*   Use this data to update your app's state and navigate to the comment's location.

The event handler receives an object with the following properties:

| Property          | Type              | Description                                      |
| ----------------- | ----------------- | ------------------------------------------------ |
| `documentId`      | string            | ID of the document containing the comment        |
| `location`        | Object            | Location details of the comment                  |
| `targetElementId` | string            | DOM ID of the element the comment is attached to |
| `context`         | Object            | Custom context data associated with the comment  |
| `annotation`      | CommentAnnotation | The full comment annotation object               |

<Tabs>
  <Tab title="React / Next.js">
    ```js
     <VeltCommentsSidebar onCommentClick={onCommentClick} /> 

    // event handler for when a comment is clicked on 
    const onCommentClick = (event) => {
      //handle custom navigation by getting location if you have used Locations
      const { pageId } = event.location;
      //handle custom navigation by getting context if you have used addContext()
      const { pageId } = event.context;
      yourNavigateToPageMethod(pageId);
    };
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js

    // event handler for when a comment is clicked on 
    const onCommentClick = (event) => {
      //handle custom navigation by getting location if you have used Locations
      const { pageId } = event.location;
      //handle custom navigation by getting context if you have used addContext()
      const { pageId } = event.context;
      yourNavigateToPageMethod(pageId);
    };

    const commentElement = document.querySelector('velt-comments-sidebar');
    commentElement.addEventListener('onCommentClick', onCommentClick);
    ```
  </Tab>
</Tabs>

## 2. Custom filtering, sorting and grouping

*   Here is the overview on how it works:
    *   Enable custom actions in the comments sidebar.
    *   Add action buttons to the sidebar wireframe.
    *   Implement callback and event handlers to handle custom filtering, sorting, and grouping logic.
    *   Set custom filtered data in the comments sidebar.
*   Here are the steps to implement it:

<Steps titleSize="h2">
  <Step title="Enable Custom Actions">
    <Tabs>
      <Tab title="React / Next.js">
        Using Props:

        ```jsx
        <VeltCommentsSidebar customActions={true} />
        ```

        Using API:

        ```javascript
        commentElement.enableSidebarCustomActions();
        commentElement.disableSidebarCustomActions();
        ```
      </Tab>

      <Tab title="Other Frameworks">
        Using Props:

        ```html
        <velt-comments-sidebar custom-actions="true"></velt-comments-sidebar>
        ```

        Using API:

        ```javascript
        commentElement.enableSidebarCustomActions();
        commentElement.disableSidebarCustomActions();
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add action buttons to the sidebar wireframe">
    *   Specify an `id` to the action button. This can be used to identify which button was clicked/toggled in the callback or lifecycle events.
    *   There are two types of action buttons available:
        *   `toggle`: This button has on and off states. This can be used to enable `AND` logic.
        *   `default`: This button has only one state. This can be used to take action on click eg: sort, filter or group by a field.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentsSidebarWireframe.ActionButton id="all" type="toggle" />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comments-sidebar-action-button-wireframe id="unread" type="toggle">
        </velt-comments-sidebar-action-button-wireframe>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Set default actions">
    *   Set default custom sorting and filtering options in the comments sidebar.
    *   When the sidebar is initialized, the default actions will be applied.
    *   The keys of the object are the IDs of the action buttons you defined in the wireframe.

    ```javascript
    commentElement.setCommentSidebarDefaultCustomActions({
      'all': true,
      'unread': false,
      'mentions': false,
      'current-clip': false
    });
    ```
  </Step>

  <Step title="Implement custom filtering, sorting, and grouping logic">
    *   Handle lifecycle and click events to implement custom filtering, sorting, and grouping logic:
        *   `onCommentSidebarActionButtonClick`: Triggered when an action button is clicked.
        *   `onCommentSidebarInit`: Triggered when the comments sidebar is initialized.
        *   `onCommentSidebarData`: Triggered when the comments sidebar data is updated.

    *   The events/lifecycle methods return a [CommentSidebarCustomActionEventData](/api-reference/models/CommentSidebarCustomActionEventData) object containing:

        *   `actions`: Map of custom action button states
        *   `data`: All unfiltered comment annotations
        *   `unreadDataMap`: Map of unread comment counts by annotation ID
        *   `systemFilteredData`: Comment annotations filtered by system filters

        <Tabs>
          <Tab title="React / Next.js">
            ```jsx
            import { useCommentSidebarActionButtonClick, useCommentSidebarInit, useCommentSidebarData } from '@veltdev/react';

            const commentSidebarActionButtonClickData: CommentSidebarCustomActionEventData = useCommentSidebarActionButtonClick();
            const commentSidebarInitData: CommentSidebarCustomActionEventData = useCommentSidebarInit();
            const commentSidebarData: CommentSidebarCustomActionEventData = useCommentSidebarData();

            useEffect(() => {
              if (commentSidebarActionButtonClick) {
                // Custom Filtering | Sorting | Grouping Logic
              }
            }, [commentSidebarActionButtonClickData]);

            useEffect(() => {
              if (commentSidebarInit) {
                // Custom Filtering | Sorting | Grouping Logic
              }
            }, [commentSidebarInitData]);

            useEffect(() => {
              if (commentSidebarData) {
                // Custom Filtering | Sorting | Grouping Logic
              }
            }, [commentSidebarData]);
            ```
          </Tab>

          <Tab title="Other Frameworks">
            ```javascript
            const commentElement = Velt.getCommentElement();
            commentElement.onCommentSidebarActionButtonClick().subscribe((data) => {
              // Custom Filtering | Sorting | Grouping Logic
            });

            commentElement.onCommentSidebarInit().subscribe((data) => {
              // Custom Filtering | Sorting | Grouping Logic
            });

            commentElement.onCommentSidebarData().subscribe((data) => {
              // Custom Filtering | Sorting | Grouping Logic
            });
            ```
          </Tab>
        </Tabs>
  </Step>

  <Step title="Set custom filtered data">
    *   Once you have applied your custom filtering, sorting, and grouping logic, create the data an **array** of [CommentSidebarData](/api-reference/models/CommentSidebarData) objects and set it in the comments sidebar.
    *   Use the `options` parameter to control if you want to group the comments or not.
        <Tabs>
          <Tab title="React / Next.js">
            ```jsx
            const options = {
              grouping: false
            };

            const customFilterData = [
              {
                "groupId": "group1",
                "groupName": "Group 1",
                "isExpanded": true,
                "annotations": [
                  {
                      ...annotation1
                  },
                  {
                      ...annotation2
                  },
                ]
              }
            ];

            const commentElement = client.getCommentElement();
            commentElement.setCommentSidebarData(customFilterData, options);
            ```
          </Tab>

          <Tab title="Other Frameworks">
            ```javascript
            const options = {
              grouping: false
            };
            const customFilterData = [
              {
                "groupId": "group1",
                "groupName": "Group 1",
                "isExpanded": true,
                "annotations": [
                  {
                      ...annotation1
                  },
                  {
                      ...annotation2
                  },
                ]
              }
            ];
            const commentElement = Velt.getCommentElement();
            commentElement.setCommentSidebarData(customFilterData, options);
            ```
          </Tab>
        </Tabs>
  </Step>
</Steps>

## 3. Add composer to sidebar with Page mode

*   This adds a composer in the sidebar where users can add comments without attaching them to any specific element.

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebar pageMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments-sidebar page-mode="true"></velt-comments-sidebar>
    ```
  </Tab>
</Tabs>

## 4. Embed Sidebar in your component

*   By default, the sidebar will open up from the right corner of the page.
*   With embed mode, you can add the sidebar in your component and it will take up the full width and height of its container.
*   When in embed mode, the sidebar will not have the close button. You need to implement your own open and close functionality on the host component.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <div className="sidebar-container">
      <VeltCommentsSidebar embedMode={true} />
    </div>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <div className="sidebar-container">
      <velt-comments-sidebar embed-mode="true"></velt-comments-sidebar>
    </div>
    ```
  </Tab>
</Tabs>

## 5. Exclude comments from certain locations

*   Use this to filter out comments from certain locations. These comments will not be displayed in the sidebar.

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltCommentsSidebar excludeLocationIds={['location1', 'location2']} />
    ```

    Using API:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.excludeLocationIdsFromSidebar(['location1', 'location2']);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```jsx
    <velt-comments-sidebar exclude-location-ids='["location1", "location2"]'></velt-comments-sidebar>
    ```

    Using API:

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.excludeLocationIdsFromSidebar(['location1', 'location2']);
    ```
  </Tab>
</Tabs>

## 6. Floating mode

*   This makes the sidebar open in an overlay panel over the sidebar button float over the page content.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltSidebarButton floatingMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-sidebar-button floating-mode="true"></velt-sidebar-button>
    ```
  </Tab>
</Tabs>

## 7. Change sidebar open position

*   Change the default direction where the sidebar opens from.
*   Options: `left` or `right`
*   Default: `right`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebar position="left"/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments-sidebar position="left"/>
    ```
  </Tab>
</Tabs>

## 8. Enable/Disable Sidebar URL Navigation

*   By default, clicking a comment in the sidebar doesn't automatically update the page URL where the comment was added.
*   Use this to enable automatic URL navigation when clicking comments in the sidebar.
*   If your app's state is more complex, you might need to listen for `onCommentClick` events and implement custom navigation logic.

Default: `false`

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltCommentsSidebar urlNavigation={true} />
    ```

    Using API method:

    ```js
    const commentElement = client.getCommentElement();
    // to enable sidebar url navigation
    commentElement.enableSidebarUrlNavigation();
    // to disable sidebar url navigation
    commentElement.disableSidebarUrlNavigation();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```js
    <velt-comments-sidebar url-navigation="false"></velt-comments-sidebar>
    ```

    Using API method:

    ```js
    const commentElement = Velt.getCommentElement();
    commentElement.enableSidebarUrlNavigation();
    commentElement.disableSidebarUrlNavigation();
    ```
  </Tab>
</Tabs>

## 9. Open/close the Comments Sidebar

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.openCommentSidebar(); // opens the comments side bar
    commentElement.closeCommentSidebar(); // closes the comments side bar
    commentElement.toggleCommentSidebar(); // toggles the comments side bar
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.openCommentSidebar(); // opens the comments side bar
    commentElement.closeCommentSidebar(); // closes the comments side bar
    commentElement.toggleCommentSidebar(); // toggles the comments side bar
    ```
  </Tab>
</Tabs>

## 10. Enable/disable "this page" suffix

*   Adds "(this page)" suffix to the group name when the current location matches the group's location.

Default: `false`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebar currentLocationSuffix={true}/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments-sidebar current-location-suffix="true"></velt-comments-sidebar>
    ```
  </Tab>
</Tabs>

## 11. System Filters Customization

*   Customize the available system filters:
*   `location`
*   `people`
*   `priority`
*   `category`
*   You can rename, disable, configure grouping, and multi-select behavior of the filters as needed.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const filterConfig = {
      location: {
        enable: true,
        name: "Pages", // change the display name of the filter
        enableGrouping: true, // whether to enable grouping based on location filter
        multiSelection: true, // whether to enable multiselection for the filter
        order: ['locationId1', 'locationId2', 'locationId3'] // change the order of the filter options
      },
      people: {
        enable: true,
        name: "People", // change the display name of the filter
        enableGrouping: true, // whether to enable grouping based on people filter
        multiSelection: true, // whether to enable multiselection for the filter
      },
      priority: {
        enable: true,
        name: "Priority", // change the display name of the filter
        enableGrouping: false, // whether to enable grouping based on priority filter
        multiSelection: true, // whether to enable multiselection for the filter
      },
      category: {
        enable: true,
        name: "Category", // change the display name of the filter
        enableGrouping: true, // whether to enable grouping based on category filter
        multiSelection: true, // whether to enable multiselection for the filter
      }
    }

    <VeltCommentsSidebar filterConfig={filterConfig} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const filterConfig = {
      location: {
        enable: true, // enable/disable location filter
        name: "Pages", // customize location filter heading
        enableGrouping: true, // to enable/disable grouping based on location filter
        multiSelection: true, // to enable/disable multiple selection
        order: ['locationId1', 'locationId2', 'locationId3'] // pass array of location ids here
      },
      people: {
        enable: true, // enable/disable people filter
        name: "People", // customize people filter heading
        enableGrouping: true, // to enable/disable grouping based on people filter
        multiSelection: true, // to enable/disable multiple selection
      },
      priority: {
        enable: true, // enable/disable priority filter
        name: "Priority", // customize priority filter heading
        enableGrouping: false, // to enable/disable grouping based on priority filter
        multiSelection: true, // to enable/disable multiple selection
      },
      category: {
        enable: true, // enable/disable category filter
        name: "Category", // customize category filter heading
        enableGrouping: true, // to enable/disable grouping based on category filter
        multiSelection: true, // to enable/disable multiple selection
      }
    };

    const commentsSidebar = document.querySelector(`velt-comments-sidebar`);
    commentsSidebar?.setAttribute("filter-config", JSON.stringify(filterConfig));
    ```
  </Tab>
</Tabs>

## 12. System Grouping Customization

*   Enable/disable the option to group comments in the sidebar with the `group config` attribute:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const groupConfig = {
      enable: true, // whether to enable group by option
      name: "Custom Group By", // change the display name of the group by option in the filter panel
    };

    <VeltCommentsSidebar groupConfig={groupConfig} />

    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const groupConfig = {
      enable: true, // whether to enable group by option
      name: "Custom Group By", // change the display name of the group by option in the filter panel
    };


    const commentsSidebar = document.querySelector(`velt-comments-sidebar`);
    commentsSidebar?.setAttribute("group-config", JSON.stringify(groupConfig));

    ```
  </Tab>
</Tabs>

## 13. System Sorting Customization

*   Change the default sorting order of Comments in the Sidebar.
*   Default: `desc`

There are three options for sorting:

*   `asc` - to show comments in ascending order of when they were last updated
*   `desc` - to show comments in descending order of when they were last updated
*   `none` - to show comments in the sequence they were added

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebar sortData="asc" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments-sidebar sort-data="asc"></velt-comments-sidebar>
    ```
  </Tab>
</Tabs>

## 14. Apply System Filters Programmatically

*   Programmatically set the system filters on the sidebar:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const filters = {
    	location: [
    		{ id: 'location1Id' }, // id field is required
    		{ id: 'location2Id' }, // id field is required
    	],
    	people: [
    		{ userId: 'userIdToFilter' }, // userId or
    		{ email: 'userEmailToFilter' } // user email is required
    	],
    	priority: ['P0', 'P1', 'P2'], // default supported values
    	status: ['OPEN', 'IN_PROGRESS', 'RESOLVED'], // default supported values
    	category: ['bug', 'feedback', 'question'], // default supported values
    };


    <VeltCommentsSidebar filters={filters} />
    ```

    API Methods:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.setCommentSidebarFilters(filters);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const filters = {
    	location: [
    		{ id: 'location1Id' }, // id field is required
    		{ id: 'location2Id' }, // id field is required
    	],
    	people: [
    		{ userId: 'userIdToFilter' }, // userId or
    		{ email: 'userEmailToFilter' } // user email is required
    	],
    	priority: ['P0', 'P1', 'P2'], // default supported values
    	status: ['OPEN', 'IN_PROGRESS', 'RESOLVED'], // default supported values
    	category: ['bug', 'feedback', 'question'], // default supported values
    };

    const commentsSidebar = document.querySelector(`velt-comments-sidebar`);
    commentsSidebar?.setAttribute("filters", JSON.stringify(filters));
    ```

    API Methods:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.setCommentSidebarFilters(filters);
    ```
  </Tab>
</Tabs>

## 15. Filter panel layout customization

*   Change the layout of the filter panel in the sidebar.
*   Options: `menu` or `bottomSheet`
    `Default: bottomSheet`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebar filterPanelLayout="menu"/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments-sidebar filter-panel-layout="menu"/>
    ```
  </Tab>
</Tabs>

## 16. Focused Thread Mode

*   In this mode, when you click on a comment in the sidebar, it opens the thread in an expanded view within the sidebar itself.
*   Other threads and actions like filters, search etc. are hidden behind a back button.
*   Enabling this mode also adds a navigation button in the comment dialog. Clicking it will navigate to the comment and trigger a callback.
*   If you had previously used a wireframe for the comment dialog, you will need to add the [navigation button wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/header) and the [focused thread wireframe](/ui-customization/features/async/comments/comments-sidebar/overview).

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebar focusedThreadMode={true} />
    ```

    **Handling the navigation button click:**

    ```jsx
    <VeltCommentsSidebar onCommentNavigationButtonClick={onCommentNavigationButtonClick} />

      // event handler for when a comment is clicked on 
      const onCommentNavigationButtonClick = (event) => {
        console.log('onCommentNavigationButtonClick', event);
        //handle custom navigation by getting location if you have used Locations
        const { pageId } = event.location;
        //handle custom navigation by getting context if you have used addContext()
        const { pageId } = event.context;
        yourNavigateToPageMethod(pageId);
      };
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comments-sidebar focused-thread-mode="true"></velt-comments-sidebar>
    ```

    **Handling the navigation button click:**

    ```javascript
    const commentSidebarElement = document.querySelector('velt-comments-sidebar');
    commentSidebarElement.addEventListener('onCommentNavigationButtonClick', (s) => {
      console.log('onCommentNavigationButtonClick', s.detail);
    });
    ```
  </Tab>
</Tabs>


# Comments Sidebar

Provide a toggleable sidebar to view and filter comments.

The Velt SDK contains 4 components that can be used to control the Comments Sidebar functionality:

*   `VeltComments` - Used to enable the Comments feature site wide
*   `VeltCommentsSidebar` - The Sidebar that holds all existing comments
*   `VeltSidebarButton` - A button that toggles the `VeltCommentsSidebar`on and off
*   `VeltCommentTool` - A button that turns on the Comments functionality

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comments&type=sidebar" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comments\&type=sidebar)


# Setup



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Comments Sidebar Components">
        Import the Comments Sidebar Components.

        ```jsx
        import { 
          VeltProvider, 
          VeltCommentsSidebar, 
          VeltSidebarButton,
          VeltCommentTool 
        } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Comments and Sidebar components">
        Add the `VeltComments` and `VeltCommentsSidebar` components to the root of your app.

        ```jsx
        <div>
          <VeltComments />
          <VeltCommentsSidebar />
        </div>
        ```
      </Step>

      <Step title="Add Sidebar button and Comment Tool component">
        Add the Sidebar button to toggle the sidebar. Add the `VeltCommentTool` component to leave comments.

        ```jsx
        <div className="toolbar">
          <VeltSidebarButton />
          <VeltCommentTool />
        </div>
        ```

        This is completely optional and you can toggle the sidebar in the comment dialog as well.
      </Step>

      <Step title="Test Integration">
        Test it out by opening the sidebar.

        You should be able to click the `All comments` link in a comment dialog box on the bottom.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Place the <velt-comments-sidebar> component">
        Place the `<velt-comments-sidebar>` component at the root of your app.

        ```html
        <velt-comments-sidebar></velt-comments-sidebar>
        ```
      </Step>

      <Step title="Place the <velt-sidebar-button> component">
        Place the `<velt-sidebar-button>` component wherever you want the toggle button to appear.

        ```html
        <velt-sidebar-button></velt-sidebar-button>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { 
    VeltProvider, 
    VeltCommentsSidebar, 
    VeltSidebarButton,
    VeltCommentTool 
  } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">
        <VeltComments /> {/* Add VeltComments to the root of your app provider */}
        <VeltCommentsSidebar /> {/* Add VeltCommentsSidebar to the root of your app provider */}

        <div className="toolbar">
          <VeltCommentTool /> {/* Add VeltCommentTool wherever you want it to appear */}
          <VeltSidebarButton /> {/* Add VeltCommentSideBarButton wherever you want it to appear */}
        </div>

      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");
        }
      </script>
    </head>
    <body>
      <velt-comments></velt-comments> <!-- add to the root of your app-->
      <velt-comments-sidebar></velt-comments-sidebar> <!-- add to the root of your app -->
      <div class="toolbar"> <!-- a component representing a toolbar-->
        <velt-comment-tool></velt-comment-tool> <!-- add wherever you want it to appear-->
        <velt-sidebar-button></velt-sidebar-button> <!-- add wherever you want it to appear -->
      </div>
      

    </body>
  </html>
  ```
</RequestExample>


# Customize Behavior



# @Mentions

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

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/enable-@-here.png)

<Tabs>
  <Tab title="React / Next.js">
    **Hooks:**

    ```jsx
    const contactElement = useContactUtils();

    useEffect(() => {
      contactElement.enableAtHere();
      contactElement.disableAtHere();
    }, [contactElement]);

    ```

    **API:**

    ```jsx
    const contactElement = client.getContactElement();
    contactElement.enableAtHere();
    contactElement.disableAtHere();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const contactElement = Velt.getContactElement();
    contactElement.enableAtHere();
    contactElement.disableAtHere();
    ```
  </Tab>
</Tabs>

#### enableUserMentions

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

Whether user @mentions are enabled.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltComments userMentions={false} />
    ```

    **Using Hooks:**

    ```jsx
    const contactElement = useContactUtils();

    useEffect(() => {
      contactElement.enableUserMentions();
      contactElement.disableUserMentions();
    }, [contactElement]);
    ```

    **Using API Method:**

    ```jsx
    const contactElement = client.getContactElement();
    contactElement.enableUserMentions();
    contactElement.disableUserMentions();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using props:**

    ```jsx
    <velt-comments user-mentions="false"></velt-comments>
    ```

    **Using API Method:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableUserMentions(); // to enable user mentions
    commentElement.disableUserMentions(); // to disable user mentions
    ```
  </Tab>
</Tabs>

#### 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
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.
}
```

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx
    const selectedContact = useContactSelected();

    useEffect(() => {
      console.log('selectedContact: ', selectedContact);
    }, [selectedContact]);

    ```

    **Using API:**

    ```jsx
    const contactElement = client.getContactElement();

    contactElement.onContactSelected().subscribe((selectedContact: any) => {
      console.log('selectedContact : ', selectedContact);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const contactElement = Velt.getContactElement();

    contactElement.onContactSelected().subscribe((selectedContact: any) => {
      console.log('selectedContact: ', selectedContact);
    });
    ```
  </Tab>
</Tabs>

#### setAtHereLabel

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

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments atHereLabel='@all'>
    ```

    **Using Hooks:**

    ```jsx
    const contactElement = useContactUtils();

    useEffect(() => {
      contactElement.setAtHereLabel('@all');
    }, [contactElement]);
    ```

    **Using API Method:**

    ```jsx
    const contactElement = client.getContactElement();
    contactElement.setAtHereLabel('@all');
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments at-here-label="@all">
    ```

    **Using API Method:**

    ```jsx
    const contactElement = Velt.getContactElement();
    contactElement.setAtHereLabel('@all');
    ```
  </Tab>
</Tabs>

#### setAtHereDescription

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

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments atHereDescription="Notify all users in this document" />
    ```

    **Using Hooks:**

    ```jsx
    const contactElement = useContactUtils();

    useEffect(() => {
      contactElement.setAtHereDescription('Notify all users in this document');
    }, [contactElement]);
    ```

    **Using API Method:**

    ```jsx
    const contactElement = client.getContactElement();
    contactElement.setAtHereDescription('Notify all users in this document');
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments at-here-description="Notify all users in this document"></velt-comments>
    ```

    **Using API Method:**

    ```javascript
    const contactElement = Velt.getContactElement();
    contactElement.setAtHereDescription('Notify all users in this document');
    ```
  </Tab>
</Tabs>

#### 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}`.
*   This method will only update the contact list in the current user session. It doens't update the user contacts in the database or change the access control.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx
    const contactElement = useContactUtils();

    useEffect(() => {
      contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: false});
    }, [contactElement]);

    ```

    **Using API:**

    ```jsx
    const contactElement = client.getContactElement();
    contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: false});
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const contactElement = Velt.getContactElement();
    contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: false});
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const contactElement = client.getContactElement();
    contactElement.updateContactListScopeForOrganizationUsers(['all', 'organization', 'organizationUserGroup', 'document']);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const contactElement = Velt.getContactElement();
    contactElement.updateContactListScopeForOrganizationUsers(['all', 'organization', 'organizationUserGroup', 'document']);
    ```
  </Tab>
</Tabs>

# 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 the `event.addContext()` method when a comment is added. This method accepts an object with key-value pairs.

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/addContext.png)

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```js
    <VeltComments onCommentAdd={(event) => 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?.addContext({ customKey: 'customValue' });
      }, [commentAddEvent]);

      return (
        <div></div>
      )
    }
    ```

    Using API method:

    ```js
    const commentElement = client.getCommentElement();

    commentElement.onCommentAdd().subscribe((event) => {
      event?.addContext({ customKey: 'customValue' });
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    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' });
    });
    ```
  </Tab>
</Tabs>

#### updateContext

You can update the custom metadata associated with a comment annotation using the `updateContext` method. This method is available in two scenarios:

1.  **In the `onCommentUpdate` event callback:**
    Use this to update the context when a comment is modified.

2.  **Via the `updateContext` API 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.

**Option 1: onCommentUpdate event**
The `updateContext` method accepts two parameters:

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

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```js
    <VeltComments onCommentUpdate={(event) => yourMethod(event)} />

    const yourMethod = (event) => {
      console.log('commentUpdateEvent', event);
      event?.updateContext({ customKey: 'customValue' }, { merge: true });
    }
    ```

    Using Hooks:

    ```jsx
    import { useCommentUpdateHandler} from '@veltdev/react';

    export default function YourDocument() {

      const commentUpdateEvent = useCommentUpdateHandler();
      useEffect(() => {
        console.log('commentUpdateEvent', commentUpdateEvent);
        commentUpdateEvent?.updateContext({ customKey: 'customValue' }, { merge: true });
      }, [commentUpdateEvent]);

      return (
        <div></div>
      )
    }
    ```

    Using API:

    ```js
    const commentElement = client.getCommentElement();

    commentElement.onCommentUpdate().subscribe((event) => {
      console.log('commentUpdateEvent', event);
      event?.updateContext({ customKey: 'customValue' }, { merge: true });
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Event Listener:

    ```js
    const veltCommentsTag = document.querySelector('velt-comments');

    veltCommentsTag?.addEventListener('onCommentUpdate', (event) => {
      console.log('*** onCommentUpdate ***');
      console.log(event.detail);
      event.detail?.updateContext({ customKey: 'customValue' }, { merge: true });
    });
    ```

    Using API method:

    ```js
    const commentElement = Velt.getCommentElement();

    commentElement.onCommentUpdate().subscribe((event) => {
      console.log('commentUpdateEvent', event);
      event?.updateContext({ customKey: 'customValue' }, { merge: true });
    });
    ```
  </Tab>
</Tabs>

**Option 2: commentElement.updateContext**

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)

<Tabs>
  <Tab title="React / Next.js">
    Using API:

    ```js

    const updatedContext = { customKey: 'customValue' };
    const updateContextConfig = { merge: true };

    const commentElement = client.getCommentElement();
    commentElement.updateContext(COMMENT_ANNOTATION_ID, updatedContext, updateContextConfig);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using API method:

    ```js
    const updatedContext = { customKey: 'customValue' };
    const updateContextConfig = { merge: true };

    const commentElement = client.getCommentElement();
    commentElement.updateContext(COMMENT_ANNOTATION_ID, updatedContext, updateContextConfig);
    ```
  </Tab>
</Tabs>

# 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://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/comment-annotation-custom-list.png)

```jsx
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
};
```

<Tabs>
  <Tab title="React / Next.js with hooks">
    **Using Props:**

    ```jsx
    <VeltComments customListDataOnAnnotation={customListDataOnCommentAnnotation} />
    ```

    **API Method:**

    ```jsx
    const commentElement = useCommentUtils();		
    commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
    ```
  </Tab>

  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments customListDataOnAnnotation={customListDataOnCommentAnnotation} />
    ```

    **API Method:**

    ```jsx
    const commentElement = client.getCommentElement();		
    commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();			
    commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
    ```
  </Tab>
</Tabs>

#### 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://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/custom-list-1.png)

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

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/custom-list-2.png)

<Steps titleSize="h2">
  <Step title="Set hotkey and list data">
    <Warning> Make sure the hotkey is a single character such as `#` or `/`</Warning>

    *   Create the list of data will be shown when the `hotkey` is pressed. Eg: When the user presses `#`, the list of files or links from other parts of your app is shown.
    *   The items in the list must be in the following schema:

    ```jsx
    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. This appears as the icon in the UI.
        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.
    }
    ```

    ```jsx
    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 charater is allowed. eg: '#'
    	type: 'custom',
        data: customList, // your customList data here
    };
    ```

    <Tabs>
      <Tab title="React / Next.js with hooks">
        **Using Props:**

        ```jsx
        <VeltComments customListDataOnComment={customListDataOnComment} />
        ```

        **API Method:**

        ```jsx
        const commentElement = useCommentUtils();		
        commentElement.createCustomListDataOnComment(customListDataOnComment);
        ```
      </Tab>

      <Tab title="React / Next.js">
        **Using Props:**

        ```jsx
        <VeltComments customListDataOnComment={customListDataOnComment} />
        ```

        **API Method:**

        ```jsx
        const commentElement = client.getCommentElement();		
        commentElement.createCustomListDataOnComment(customListDataOnComment);
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        const commentElement = Velt.getCommentElement();			
        commentElement.createCustomListDataOnComment(customListDataOnComment);
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Listen to click event data 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).

    <Info>This event will also be triggered when the user clicks on the contact chips added via the @mentions feature.</Info>

    <Tabs>
      <Tab title="React / Next.js with Hooks">
        ```jsx
        let autocompleteChipData = useAutocompleteChipClick(); 
        ```
      </Tab>

      <Tab title="React / Next.js">
        ```jsx
        const autocompleteElement = client.getAutocompleteElement();
        const subscription = autocompleteElement.onAutocompleteChipClick().subscribe(_data => {
            console.log(_data);
        })
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        const autocompleteElement = Velt.getAutocompleteElement();
        const subscription = autocompleteElement.onAutocompleteChipClick().subscribe(_data => {
            console.log(_data);
        })
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

# Threads

#### addCommentOnSelectedText

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/addCommentOnSelectedText.png)

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:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    // to add comment on selected text
    commentElement.addCommentOnSelectedText();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    // to add comment on selected text
    commentElement.addCommentOnSelectedText();
    ```
  </Tab>
</Tabs>

#### addCommentOnElement

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/addCommentOnElement.png)

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 shows in the example:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx

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

  <Tab title="Other Frameworks">
    ```jsx

    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 occurence 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);
    ```
  </Tab>
</Tabs>

#### 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 the this method to create a comment with custom metadata.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const context = {
      postion: {x: 200, y: 100},
    };
    const commentElement = client.getCommentElement();
    const config: ManualCommentAnnotationConfig = {
    	context: context, // your context here
    };
    commentElement.addManualComment(config);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const context = {
      postion: {x: 200, y: 100},
    };
    const commentElement = Velt.getCommentElement();
    const config: ManualCommentAnnotationConfig = {
    	context: context, // your context here
    };
    commentElement.addManualComment(config);
    ```
  </Tab>
</Tabs>

#### deleteSelectedComment

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/deleteSelectedComment.png)

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    if (client) {
      const commentElement = client.getCommentElement();
      commentElement.deleteSelectedComment();
    }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    if (Velt) {
      const commentElement = Velt.getCommentElement();
      commentElement.deleteSelectedComment();
    }
    ```
  </Tab>
</Tabs>

#### getElementRefByAnnotationId

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/getElementRefByAnnotationId.png)

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    let elementRef = commentElement.getElementRefByAnnotationId('annotationId')

    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    let elementRef = commentElement.getElementRefByAnnotationId('annotationId')

    ```
  </Tab>
</Tabs>

#### onCommentAdd

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/onCommentAdd.png)

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```js
    <VeltComments onCommentAdd={(event) => 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 (
        <div></div>
      )
    }
    ```

    Using API:

    ```js
    const commentElement = client.getCommentElement();

    commentElement.onCommentAdd().subscribe((event) => {
      console.log('commentAddEvent', event);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    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' });
    });
    ```
  </Tab>
</Tabs>

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

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/onCommentUpdate.png)

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```js
    <VeltComments onCommentUpdate={(event) => 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 (
        <div></div>
      )
    }
    ```

    Using API:

    ```js
    const commentElement = client.getCommentElement();

    commentElement.onCommentUpdate().subscribe((event) => {
      console.log('commentUpdateEvent', event);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    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);
    });
    ```
  </Tab>
</Tabs>

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

#### getAllCommentAnnotations

<Tabs>
  <Tab title="React / Next.js with Hooks">
    To retreive all comments in the frontend, use the `useCommentAnnotations()` hook. The hook will return an array that contains all current comments.

    Whenever there is a change to the comments structure, the hook return value will be updated to the latest change.

    The hook will automatically unsubscribe from the subscription when the component dismounts.

    ```jsx
    import { useCommentAnnotations } from '@veltdev/react';

    export default function YourDocument() {

      let commentAnnotations = useCommentAnnotations()

      return (
        <div>
           {commentAnnotations.map(x => <div>{x.annotationId}</div>)}
        </div>
      )
    }
    ```

    By default, `useCommentAnnotations()` will return data for the current `documentId` and `location`.

    If you pass in a `documentId` as an argument, it will return all comments in the given `documentId`.

    If you pass in a `documentId` as the first argument and a `location` object as the second argument, it will return all comments in the given `documentId` and `location`.

    ```jsx
    import { useCommentAnnotations } from '@veltdev/react';

    export default function YourDocument() {

      let commentAnnotations = useCommentAnnotations('my-document-id', { id:'my-location-id',locationName:"MyLocationName"})

      return (
        <div>
           {commentAnnotations.map(x => <div>{x.annotationId}</div>)}
        </div>
      )
    }
    ```
  </Tab>

  <Tab title="React / Next.js">
    To retrieve all comments in the frontend, use the `commentElement.getAllCommentAnnotations()` method and subscribe with a callback function.

    Whenever there is a change to the comments structure, the callback function will be triggered and will contain all current comments in an array.

    ```js
    if (client) {
      const commentElement = client.getCommentElement();
      let subscription = commentElement.getAllCommentAnnotations().subscribe((comments) => {
        // Do something with comments
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```

    By default, `getAllCommentAnnotations` will return data for the current `documentId` and `location`.

    If you pass in a `documentId` to `getAllCommentAnnotations` as an argument, it will return all comments in the given `documentId`.

    If you pass in a `documentId` as the first argument and a `location` object as the second argument, it will return all comments in the given `documentId` and `location`.

    ```js
    if (client) {
      const commentElement = client.getCommentElement();
      let subscription = commentElement.getAllCommentAnnotations('my-document-id', { id:'my-location-id',locationName:"MainVideoPlayer",timestamp:120}).subscribe((comments) => {
        // Get comments with my-document-id and my-locaiton-id
      });
    }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    To retrieve all comments in the frontend, call getCommentElement() on the Velt client and then `subscribe()` to `getAllCommentAnnotations()` and pass in a callback function.

    Whenever there is a change to the comments structure, the callback function will be triggered and will contain all current comments in an array.

    ```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()
    ```

    By default, `getAllCommentAnnotations` will return data for the current `documentId` and `location`.

    If you pass in a `documentId` to `getAllCommentAnnotations` as an argument, it will return all comments in the given `documentId`.

    If you pass in a `documentId` as the first argument and a `location` object as the second argument, it will return all comments in the given `documentId` and `location`.

    ```js
    if (Velt) {
      const commentElement = Velt.getCommentElement();
      let subscription = commentElement.getAllCommentAnnotations('my-document-id', { id:'my-location-id',locationName:"MainVideoPlayer",timestamp:120}).subscribe((comments) => {
        // Get comments with my-document-id and my-locaiton-id
      });
    }
    ```
  </Tab>
</Tabs>

#### getUnreadCommentAnnotationCountOnCurrentDocument

<Tabs>
  <Tab title="React / Next.js with Hooks">
    You can get the number of `CommentAnnotations` that have at least 1 unread `Comment` on the current `Document` by using the `useUnreadCommentAnnotationCountOnCurrentDocument()` hook:

    ```jsx
    const count = useUnreadCommentAnnotationCountOnCurrentDocument();
    useEffect(() => {
      console.log(count, 'countObj')
    }, [count])
    ```
  </Tab>

  <Tab title="React / Next.js">
    You can get the number of `CommentAnnotations` that have at least 1 unread `Comment` on the current `Document` by subscribing to the `getUnreadCommentAnnotationCountOnCurrentDocument()` method:

    ```jsx
    if (client) {
      const commentElement = client.getCommentElement();
      let subscription = commentElement.getUnreadCommentAnnotationCountOnCurrentDocument().subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    You can get the number of `CommentAnnotations` that have at least 1 unread `Comment` on the current `Document` by subscribing to the `getUnreadCommentAnnotationCountOnCurrentDocument()` method:

    ```jsx
    if (Velt) {
      const commentElement = Velt.getCommentElement();
      let subscription = commentElement.getUnreadCommentAnnotationCountOnCurrentDocument().subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

#### getUnreadCommentAnnotationCountByLocationId

<Tabs>
  <Tab title="React / Next.js with Hooks">
    You can get the number of `CommentAnnotations` with at least 1 unread `Comment` by `Location Id` by using the `useUnreadCommentAnnotationCountByLocationId()` hook:

    ```jsx
    const count = useUnreadCommentAnnotationCountByLocationId(locationId);
    useEffect(() => {
      console.log(count, 'countObj')
    }, [count])
    ```
  </Tab>

  <Tab title="React / Next.js">
    You can get the number of `CommentAnnotations` with at least 1 unread `Comment` by `Location Id` by using the `getUnreadCommentAnnotationCountByLocationId` method:

    ```jsx
    if (client) {
      const commentElement = client.getCommentElement();
      let subscription = commentElement.getUnreadCommentAnnotationCountByLocationId(locationId).subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    You can get the number of `CommentAnnotations` with at least 1 unread `Comment` by `Location Id` by using the `getUnreadCommentAnnotationCountByLocationId` method:

    ```jsx
    if (Velt) {
      const commentElement = Velt.getCommentElement();
      let subscription = commentElement.getUnreadCommentAnnotationCountByLocationId(locationId).subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

#### getSelectedComments

*   Get the currently selected comment annotations.
*   This returns an array of [`CommentAnnotation`](/api-reference/models/CommentAnnotation) objects.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    const subscription = commentElement.getSelectedComments().subscribe((selectedComments) => {
      console.log('Selected comments:', selectedComments);
    });

    ```

    Unsubscribe from the subscription when you're done:

    ```jsx
    subscription?.unsubscribe()

    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const commentElement = Velt.getCommentElement();
    const subscription = commentElement.getSelectedComments().subscribe((selectedComments) => {
      console.log('Selected comments:', selectedComments);
    });
    ```

    Unsubscribe from the subscription when you're done:

    ```js
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

#### 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`.

<Tabs>
  <Tab title="React / Next.js">
    Using Hooks:

    ```jsx
    const annotation = useCommentAnnotationById({
      annotationId: '-O6W3jD0Lz3rxuDuqQFx',  // AnnotationID
      documentId: 'document-id'              // DocumentId (Optional)
    });

    useEffect(() => {
      console.log('annotation', annotation);
    }, [annotation]);
    ```

    Using API:

    ```javascript
    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
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using API:

    ```javascript
    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
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

# Messages

#### getUnreadCommentCountOnCurrentDocument

<Tabs>
  <Tab title="React / Next.js with Hooks">
    You can get the number of unread `Comments` on the current `Document` by using the `useUnreadCommentCountOnCurrentDocument()` hook:

    ```jsx
    const count = useUnreadCommentCountOnCurrentDocument();
    useEffect(() => {
      console.log(count, 'countObj')
    }, [count])
    ```
  </Tab>

  <Tab title="React / Next.js">
    You can get the number of unread `Comments` on the current `Document` by using the `getUnreadCommentCountOnCurrentDocument()` method:

    ```jsx
    if (client) {
      const commentElement = client.getCommentElement();
      let subscription = commentElement.getUnreadCommentCountOnCurrentDocument().subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    You can get the number of unread `Comments` on the current `Document` by using the `getUnreadCommentCountOnCurrentDocument()` method:

    ```jsx
    if (Velt) {
      const commentElement = Velt.getCommentElement();
      let subscription = commentElement.getUnreadCommentCountOnCurrentDocument().subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

#### getUnreadCommentCountByLocationId

<Tabs>
  <Tab title="React / Next.js with Hooks">
    You can get the number of unread `Comments` by `Location Id` by using the `useUnreadCommentCountByLocationId()` hook:

    ```jsx
    const count = useUnreadCommentCountByLocationId(locationId);
    useEffect(() => {
      console.log(count, 'countObj')
    }, [count])
    ```
  </Tab>

  <Tab title="React / Next.js">
    You can get the number of unread `Comments` by `Location Id` by using the `getUnreadCommentCountByLocationId()` method:

    ```jsx
    if (client) {
      const commentElement = client.getCommentElement();
      let subscription = commentElement.getUnreadCommentCountByLocationId(locationId).subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="React / HTML">
    You can get the number of unread `Comments` by `Location Id` by using the `getUnreadCommentCountByLocationId()` method:

    ```jsx
    if (Velt) {
      const commentElement = Velt.getCommentElement();
      let subscription = commentElement.getUnreadCommentCountByLocationId(locationId).subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

#### getUnreadCommentCountByAnnotationId

<Tabs>
  <Tab title="React / Next.js with Hooks">
    You can get the number of unread `Comments` by annotation id by using the `useUnreadCommentCountByAnnotationId()` hook:

    ```jsx
    const count = useUnreadCommentCountByAnnotationId(annotationId);
    useEffect(() => {
       console.log(count, 'countObj')
    }, [count])
    ```
  </Tab>

  <Tab title="React / Next.js">
    You can get the number of unread `Comments` by annotation id by subscribing to the `getUnreadCommentCountByAnnotationId()` method:

    ```jsx
    if (client) {
      const commentElement = client.getCommentElement();
      let subscription = commentElement.getUnreadCommentCountByAnnotationId(annotationId).subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    You can get the number of unread `Comments` by annotation id by subscribing to the `getUnreadCommentCountByAnnotationId()` method:

    ```jsx
    if (Velt) {
      const commentElement = Velt.getCommentElement();
      let subscription = commentElement.getUnreadCommentCountByAnnotationId(annotationId).subscribe((countObj) => {
        console.log(countObj);
      });
    }
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

# Reactions

#### enableReactions

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/reactions.png)

Whether emoji reactions are enabled.

Default: `true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments reactions={true} />
    ```

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableReactions();
    commentElement.disableReactions();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments reactions="true"></velt-comments>
    ```

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableReactions();
    commentElement.disableReactions();
    ```
  </Tab>
</Tabs>

#### 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`, `svg`, or `emoji` field to represent the reaction icon you want to use.

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    const customReactions = {
        "URL_EMOJI_ID": {
            "url": "EMOJI_URL"
        },
        "SVG_EMOJI_ID": {
            "svg": "EMOJI_SVG"
        },
        "TEXT_EMOJI_ID": {
            "emoji": "🤣" // emoji as a text
        }
    };

    <VeltComments customReactions={customReactions} />
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();

    const customReactions = {
        "URL_EMOJI_ID": {
            "url": "EMOJI_URL"
        },
        "SVG_EMOJI_ID": {
            "svg": "EMOJI_SVG"
        },
        "TEXT_EMOJI_ID": {
            "emoji": "🤣" // emoji as a text
        }
    }
    commentElement.setCustomReactions(customReactions);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments
      custom-reactions='{"fire_url":{"url":"https://em-content.zobj.net/source/apple/391/fire_1f525.png"},"svg_face":{"svg":"EMOJI_SVG"},"text_emoji":{"emoji":"🤣"}}'>
    </velt-comments>
    ```

    **Using API:**

    ```jsx
    const commentElement = Velt.getCommentElement();

    const customReactions = {
        "URL_EMOJI_ID": {
            "url": "EMOJI_URL"
        },
        "SVG_EMOJI_ID": {
            "svg": "EMOJI_SVG"
        },
        "TEXT_EMOJI_ID": {
            "emoji": "🤣" // emoji as a text
        }
    }
    commentElement.setCustomReactions(customReactions);
    ```
  </Tab>
</Tabs>

# Attachments

#### enableAttachments

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/file-attachment.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments attachments={true} />
    ```

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableAttachments();
    commentElement.disableAttachments();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments attachments="true"></velt-comments>
    ```

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableAttachments();
    commentElement.disableAttachments();
    ```
  </Tab>
</Tabs>

# Recording

#### setAllowedRecordings

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/recorder.png)

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

Default: `"audio"`

<Tabs>
  **Using Props:**

  <Tab title="React / Next.js">
    ```jsx
    <VeltComments recordings="video,screen" />
    ```

    **Using API:**

    ```jsx
    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
    ```
  </Tab>

  **Using Props:**

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments recordings="video,screen"></velt-comments>
    ```

    **Using API:**

    ```jsx
    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
    ```
  </Tab>
</Tabs>

#### enableRecordingSummary

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/transcript-comment.png)
![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/transcript-summary.png)

Whether `Recording` summaries in `Comments` are enabled.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments recordingSummary={false} />
    ```

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableRecordingSummary();
    commentElement.disableRecordingSummary();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments recording-summary="false"></velt-comments>
    ```

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableRecordingSummary();
    commentElement.disableRecordingSummary();
    ```
  </Tab>
</Tabs>

#### enableRecordingCountdown

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/recording-countdown.gif)

Whether the Recorder countdown is enabled.

Default: `true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments recordingCountdown={false} />
    ```

    ```jsx
    const recorderElement = client.getRecorderElement();
    recorderElement.enableRecordingCountdown();
    recorderElement.disableRecordingCountdown();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments recording-countdown="false"></velt-comments>
    ```

    ```jsx
    const recorderElement = Velt.getRecorderElement();
    recorderElement.enableRecordingCountdown();
    recorderElement.disableRecordingCountdown();
    ```
  </Tab>
</Tabs>

#### enableRecordingTranscription

Controls whether to enable AI transcription for recordings.

Default: `enabled`

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments recordingTranscription={false} />
    ```

    **Using API Methods:**

    ```javascript
    // Using comment element
    const commentElement = client.getCommentElement();
    commentElement.enableRecordingTranscription();
    commentElement.disableRecordingTranscription();

    // Or using recorder element 
    const recorderElement = client.getRecorderElement();
    recorderElement.enableRecordingTranscription();
    recorderElement.disableRecordingTranscription();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments recording-transcription="false"></velt-comments>
    ```

    **Using API Methods:**

    ```javascript
    // Using comment element
    const commentElement = Velt.getCommentElement();
    commentElement.enableRecordingTranscription();
    commentElement.disableRecordingTranscription();

    // Or using recorder element 
    const recorderElement = Velt.getRecorderElement();
    recorderElement.enableRecordingTranscription();
    recorderElement.disableRecordingTranscription();
    ```
  </Tab>
</Tabs>

# 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:**

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments minimap={true} minimapPosition="left" />
    ```

    **API Method:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableMinimap();
    commentElement.disableMinimap();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments minimap="true" minimap-position="left"></velt-comments>
    ```

    **API Method:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableMinimap();
    commentElement.disableMinimap();
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <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>

  <Tab title="Other Frameworks">
    ```jsx
    <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>
    ```
  </Tab>
</Tabs>

# Status

#### enableStatus

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/status-default.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments status={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments status="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableStatus();
    commentElement.disableStatus();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableStatus();
    commentElement.disableStatus();
    ```
  </Tab>
</Tabs>

#### setCustomStatus

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/custom-status.png)

<Tabs>
  <Tab title="React / Next.js">
    Set custom statuses in the `customStatus` prop.

    `Default statuses: Open, In Progress, Resolved`

    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.

    Setting the Status type using the `type` property:

    *   `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.

    Setting the Status Icon using the `svg` property:

    *   You can pass in a serialized SVG. We automatically parse and colorize SVGs. If instead you pass in an icon URL, you will have to colorize each icon yourself to match the status color.

    ```js
    <VeltComments customStatus={[
      {
        "id": "open",
        "name": "Open",
        "color": "white",
        "lightColor":"green",
        "type": "default",
        "svg": "<svg></svg>" // Pass in a serialized SVG
      }
    ]}/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Set custom statuses in the `custom-status` prop.

    `Default statuses: Open, In Progress, Resolved`

    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.

    Setting the Status type using the `type` property:

    *   `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.

    Setting the Status Icon using the `svg` property:

    *   You can pass in a serialized SVG. We automatically parse and colorize SVGs. If instead you pass in an icon URL, you will have to colorize each icon yourself to match the status color.

    ```js
    <velt-comments custom-status='[
      {
        "id": "open",
        "name": "Open",
        "color": "white",
        "lightColor":"green",
        "type": "default",
        "svg": "<svg></svg>" // Pass in a serialized SVG
      }
    ]'></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.setCustomStatus([
      {
        "id": "open",
        "name": "Open",
        "color": "white",
        "lightColor":"green",
        "type": "default",
        "svg": "<svg></svg>" // Pass in a serialized SVG
      }
    ])
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.setCustomStatus([
      {
        "id": "open",
        "name": "Open",
        "color": "white",
        "lightColor":"green",
        "type": "default",
        "svg": "<svg></svg>" // Pass in a serialized SVG
      }
    ])
    ```
  </Tab>
</Tabs>

<Warning>
  Make sure to have at least 2 categories set.
</Warning>

#### enableResolveButton

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/resolve-button.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments resolveButton={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments resolve-button="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableResolveButton();
    commentElement.disableResolveButton();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableResolveButton();
    commentElement.disableResolveButton();
    ```
  </Tab>
</Tabs>

# Deep Link

#### onCopyLink

You can add a callback method for when a comment link is copied. This can be useful for tracking when a comment link is copied or showing a confirmation toast to the user.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    Using Hooks:

    ```jsx
      const commentLink = useCommentCopyLinkHandler();
      useEffect(() => {
        console.log('commentLink', commentLink);
      }, [commentLink]);
    ```

    Using API:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.onCopyLink().subscribe((commentLink) => {
      console.log(commentLink);
    });
    ```
  </Tab>

  <Tab title="React / Next.js">
    Using API:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.onCopyLink().subscribe((commentLink) => {
      console.log(commentLink);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.onCopyLink().subscribe((commentLink) => {
      console.log(commentLink);
    });
    ```
  </Tab>
</Tabs>

# AI Categorization

#### enableAutoCategorize

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/ai-categories.png)

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

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments autoCategorize={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments auto-categorize="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableAutoCategorize();
    commentElement.disableAutoCategorize();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableAutoCategorize();
    commentElement.disableAutoCategorize();
    ```
  </Tab>
</Tabs>

#### setCustomCategory

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/custom-categories.png)

<Tabs>
  <Tab title="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
    <VeltComments customCategory={[
      {
        "id": "bug",
        "name": "Bug",
        "color": "red"
      }
    ]}/>
    ```
  </Tab>

  <Tab title="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
    <velt-comments customCategory='[
      {
        "id": "bug",
        "name": "Bug",
        "color": "red"
      }
    ]'></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

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

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.setCustomCategory([
      {
        "id": "bug",
        "name": "Bug",
        "color": "red"
      }
    ])
    ```
  </Tab>
</Tabs>

<Warning>
  Make sure to have at least 2 categories set.
</Warning>

# UI

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.updateCommentDialogPosition();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.updateCommentDialogPosition();
    ```
  </Tab>
</Tabs>

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

#### enableSidebarButtonOnCommentDialog

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/sidebar-button-on-comment-dialog.png)

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:

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments sidebarButtonOnCommentDialog={true} />
    ```

    **Using API methods:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableSidebarButtonOnCommentDialog()
    commentElement.disableSidebarButtonOnCommentDialog() 
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments sidebar-button-comment-dialog="true"></velt-comments>
    ```

    **Using API methods:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableSidebarButtonOnCommentDialog()
    commentElement.disableSidebarButtonOnCommentDialog() 
    ```
  </Tab>
</Tabs>

#### onSidebarButtonOnCommentDialogClick

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

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/async-collaboration/comments/customize-behavior/images/customization/onSidebarOnCommentDialogClick.png)

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments onSidebarButtonOnCommentDialogClick={(event)=>yourMethod(event)} />
    ```

    **Using Hooks:**

    ```jsx
    const commentDialogSidebarClickEvent = useCommentDialogSidebarClickHandler();
    useEffect(() => {
      console.log('CommentDialog Sidebar button clicked');
    }, [commentDialogSidebarClickEvent]);
    ```

    **Using API methods:**

    ```jsx
    const commentElement = client.getCommentElement();
    let subscription = commentElement.onSidebarButtonOnCommentDialogClick().subscribe((event) => yourMethod(event));
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="HTML">
    **Using Props:**

    ```jsx
    <velt-comments onsidebarbuttononcommentdialogclick="yourMethod(event)"></velt-comments>
    ```

    **Using API Methods:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    let subscription = commentElement.onSidebarButtonOnCommentDialogClick().subscribe((event) => yourMethod(event));
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

#### enableDeleteReplyConfirmation

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

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltComments deleteReplyConfirmation={true} />
    ```

    Using API:

    ```javascript
    const commentElement = client.getCommentElement();
    commentElement.enableDeleteReplyConfirmation();
    commentElement.disableDeleteReplyConfirmation();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-comments delete-reply-confirmation="true"></velt-comments>
    ```

    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.enableDeleteReplyConfirmation();
    commentElement.disableDeleteReplyConfirmation();
    ```
  </Tab>
</Tabs>

#### enableMobileMode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/mobile-mode.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/mobile-mode-composer.png)

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`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments mobileMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments mobile-mode="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableMobileMode();
    commentElement.disableMobileMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableMobileMode();
    commentElement.disableMobileMode();
    ```
  </Tab>
</Tabs>

#### enableCommentPinHighlighter

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/pin-highlighter-outline.png)

Wheter the pin highlighter outline is enabled or not.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments commentPinHighlighter={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments comment-pin-highlighter="false"></velt-comments>
    ```
  </Tab>
</Tabs>

API Methods:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableCommentPinHighlighter(); // to enable comment pin highlight
    commentElement.disableCommentPinHighlighter(); // to disable comment pin highlight
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableCommentPinHighlighter(); // to enable comment pin highlight
    commentElement.disableCommentPinHighlighter(); // to disable comment pin highlight
    ```
  </Tab>
</Tabs>

#### 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"`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments composerMode="expanded"/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments composer-mode="expanded"></velt-comments>
    ```
  </Tab>
</Tabs>

#### commentsOnDom

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:

<Tabs>
  <Tab title="React / Next.js">
    ```js
    {/* `true` to show comments, `false` to hide comments */}
    <VeltComments commentsOnDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <!-- `true` to show comments, `false` to hide comments -->
    <velt-comments comments-on-dom="false"></velt-comments>
    ```
  </Tab>
</Tabs>

Using API methods:

<Tabs>
  <Tab title="React / Next.js">
    ```js
    const commentElement = client.getCommentElement();
    // to show comments on DOM
    commentElement.showCommentsOnDom();
    // to hide comments on DOM
    commentElement.hideCommentsOnDom();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const commentElement = Velt.getCommentElement();
    // to show comments on DOM
    commentElement.showCommentsOnDom();
    // to hide comments on DOM
    commentElement.hideCommentsOnDom();
    ```
  </Tab>
</Tabs>

#### enableDialogOnHover

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/show-dialog-on-hover.gif)

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

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments dialogOnHover={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments dialog-on-hover="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDialogOnHover();
    commentElement.disableDialogOnHover();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDialogOnHover();
    commentElement.disableDialogOnHover();
    ```
  </Tab>
</Tabs>

#### enableFloatingCommentDialog

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/floating-comment-dialog.gif)

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

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments floatingCommentDialog={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments floating-comment-dialog="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableFloatingCommentDialog();
    commentElement.disableFloatingCommentDialog();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableFloatingCommentDialog();
    commentElement.disableFloatingCommentDialog();
    ```
  </Tab>
</Tabs>

#### showResolvedCommentsOnDom

Whether to show resolved comments on the DOM.

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments resolvedCommentsOnDom={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comments resolved-comments-on-dom="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Methods:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    // To show resolved comments on dom
    commentElement.showResolvedCommentsOnDom();
    // To hide resolved comments on dom
    commentElement.hideResolvedCommentsOnDom();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    // To show resolved comments on dom
    commentElement.showResolvedCommentsOnDom();
    // To hide resolved comments on dom
    commentElement.hideResolvedCommentsOnDom();
    ```
  </Tab>
</Tabs>

#### enableCollapsedComments

You can control whether comments inside the annotation should be collapsed.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltComments collapsedComments={false} />
    ```

    Using API:

    ```javascript
    const commentElement = client.getCommentElement();
    // To enable collapsed comments
    commentElement.enableCollapsedComments();
    // To disable collapsed comments
    commentElement.disableCollapsedComments();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-comments collapsed-comments="false"></velt-comments>
    ```

    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();
    // To enable collapsed comments
    commentElement.enableCollapsedComments();
    // To disable collapsed comments
    commentElement.disableCollapsedComments();
    ```
  </Tab>
</Tabs>

# Extra Information

#### enableCommentIndex

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/index-indicator.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments commentIndex={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments comment-index="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableCommentIndex();
    commentElement.disableCommentIndex();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableCommentIndex();
    commentElement.disableCommentIndex();
    ```
  </Tab>
</Tabs>

#### enableDeviceInfo

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/device-info.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments deviceInfo={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments device-info="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDeviceInfo();
    commentElement.disableDeviceInfo();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDeviceInfo();
    commentElement.disableDeviceInfo();
    ```
  </Tab>
</Tabs>

#### enableDeviceIndicatorOnCommentPins

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/device-info-pin.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments deviceIndicatorOnCommentPins={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments device-indicator-on-comment-pins="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDeviceIndicatorOnCommentPins();
    commentElement.disableDeviceIndicatorOnCommentPins();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDeviceIndicatorOnCommentPins();
    commentElement.disableDeviceIndicatorOnCommentPins();
    ```
  </Tab>
</Tabs>

# Comment Tool

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableCommentMode();
    commentElement.disableCommentMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableCommentMode();
    commentElement.disableCommentMode();
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="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
    import { useCommentModeState } from '@veltdev/react';

    export default function YourDocument() {

      let commentModeState = useCommentModeState()

      return (
        <div>
           Comment Mode is turned on: {commentModeState}
        </div>
      )
    }

    ```
  </Tab>

  <Tab title="React / Next.js">
    To subscribe to changes in the comment mode, use the `onCommentModeChange()` method , as a property on `VeltCommentTool`:

    ```jsx
    <VeltCommentTool onCommentModeChange={(mode) => 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()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    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()
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments commentTool={false} />
    ```

    Using API methods:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableCommentTool();
    commentElement.disableCommentTool();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments comment-tool="false"></velt-comments>
    ```

    **Using API methods:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableCommentTool();
    commentElement.disableCommentTool();
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments changeDetectionInCommentMode={true} />
    ```

    **Using API Method:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableChangeDetectionInCommentMode();
    commentElement.disableChangeDetectionInCommentMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments change-detection-in-comment-mode="true"></velt-comments>
    ```

    **Using API Method:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableChangeDetectionInCommentMode();
    commentElement.disableChangeDetectionInCommentMode();
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments persistentCommentMode={true}/>
    ```

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enablePersistentCommentMode();
    commentElement.disablePersistentCommentMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments persistent-comment-mode="true"></velt-comments> 
    ```

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enablePersistentCommentMode();
    commentElement.disablePersistentCommentMode();
    ```
  </Tab>
</Tabs>

#### setPinCursorImage

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments pinCursorImage={BASE64_IMAGE_STRING} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments pin-cursor-image="BASE64_IMAGE_STRING"></velt-comments>
    ```
  </Tab>
</Tabs>

API Methods:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.setPinCursorImage(BASE64_IMAGE_STRING);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.setPinCursorImage(BASE64_IMAGE_STRING);
    ```
  </Tab>
</Tabs>

# Navigation

#### scrollToCommentByAnnotationId

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/scroll-on-click.gif)

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.scrollToCommentByAnnotationId('annotationId')
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.scrollToCommentByAnnotationId('annotationId')
    ```
  </Tab>
</Tabs>

#### selectCommentByAnnotationId

*   Use this to programatically select a comment annotation by its id.
*   Example: If the user opens a comment url from an email notification,
    you can use this open the comment dialog after your page has finished rendering.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.selectCommentByAnnotationId("COMMENT_ANNOTATION_ID");
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.selectCommentByAnnotationId("COMMENT_ANNOTATION_ID");
    ```
  </Tab>
</Tabs>

#### onCommentSelectionChange

<Tabs>
  <Tab title="React / Next.js with Hooks">
    The `useCommentSelectionChangeHandler` hook can be used to subscribe to Comment selection changes.

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

  <Tab title="React / Next.js">
    The `onCommentSelectionChange()` method can be used to listen Comment selection changes.

    ```jsx
    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
    const commentElement = client.getCommentElement();
    let subscription = commentElement.onCommentSelectionChange().subscribe((data) => {
      console.log('onCommentSelectionChange: ', data);
    });
    ```

    **To unsubscribe from the subscription:**

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    The `onCommentSelectionChange()` method can be used to listen Comment selection changes.

    ```jsx
    <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
    export class CommentSelectionChangeData {
      selected!: boolean;
      annotation!: CommentAnnotation;
    }
    ```

    **API Methods:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    let subscription = commentElement.onCommentSelectionChange().subscribe((data) => {
      console.log('onCommentSelectionChange: ', data);
    });
    ```

    **To unsubscribe from the subscription:**

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

#### enablescrollToComment

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/scroll-on-click.gif)

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

<Tabs>
  <Tab title="React / Next.js">
    To disable the feature, set `scrollToComment` to `false`.

    ```html
    <VeltComments scrollToComment={false}/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    To disable the feature, set `scroll-to-comment` to `false`.

    ```html
    <velt-comments scroll-to-comment="false"></velt-comments>
    ```
  </Tab>
</Tabs>

API methods:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    // To enable scroll to component
    commentElement.enablescrollToComment();
    // To disable scroll to component
    commentElement.disablescrollToComment();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    // To enable scroll to component
    commentElement.enablescrollToComment();
    // To disable scroll to component
    commentElement.disablescrollToComment();
    ```
  </Tab>
</Tabs>

# DOM Controls

#### allowedElementIds

#### allowedElementClassNames

#### allowedElementQuerySelectors

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/comment-area.gif)

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.

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```js
    <VeltComments 
      allowedElementIds={['some-element']} 
      allowedElementClassNames={["class-name-1", "class-name-2"]}
      allowedElementQuerySelectors={["#id1.class-name-1"]}
    />
    ```

    **Using API Method:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.allowedElementIds['some-element'];
    commentElement.allowedElementClassNames(["class-name-1", "class-name-2"]);
    commentElement.allowedElementQuerySelectors(["#id1.class-name-1"]);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <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
    const commentElement = Velt.getCommentElement();
    commentElement.allowedElementIds['some-element'];
    commentElement.allowedElementClassNames(["class-name-1", "class-name-2"]);
    commentElement.allowedElementQuerySelectors(["#id1.class-name-1"]);
    ```
  </Tab>
</Tabs>

#### data-velt-comment-disabled

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/comment-area.gif)

Disable certain elements from being commented on.

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

```html
<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.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentTool sourceId="sourceId1" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-tool source-id="sourceId1"></velt-comment-tool>
    ```
  </Tab>
</Tabs>

# Ghost Comments

#### enableGhostComments

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/ghost-comment-pin.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/ghost-comment-dialog-box.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments ghostComments={true} />
    ```

    **Using API methods:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableGhostComments();
    commentElement.disableGhostComments();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments ghost-comments="true"></velt-comments>
    ```

    **Using API methods:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableGhostComments();
    commentElement.disableGhostComments();
    ```
  </Tab>
</Tabs>

#### enableGhostCommentsIndicator

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/ghost-comment-sidebar.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments ghostCommentsIndicator={true} />
    ```

    **Using API methods:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableGhostCommentsIndicator();
    commentElement.disableGhostCommentsIndicator();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comments ghost-comments-indicator="true"></velt-comments>
    ```

    **Using API methods:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableGhostCommentsIndicator();
    commentElement.disableGhostCommentsIndicator();
    ```
  </Tab>
</Tabs>

# Special File Type Support

#### Iframe Container Support

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/iframe-comment.png)

*   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
<div data-velt-iframe-container="true">
	<iframe src="https://www.wikipedia.org/" width="500px" height="500px"></iframe>
</div>
```

#### 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
<!-- 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>
```

# Keyboard Controls

#### enableHotkey

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

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments hotkey={false} />
    ```

    **Using API Method:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableHotkey();
    commentElement.disableHotkey();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments hotkey="true"></velt-comments>
    ```

    **Using API Method:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableHotkey();
    commentElement.disableHotkey();
    ```
  </Tab>
</Tabs>

#### 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`.

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments enterKeyToSubmit={true} />
    ```

    **Using API Method:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableEnterKeyToSubmit();
    commentElement.disableEnterKeyToSubmit();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments enter-key-to-submit="true"></velt-comments>
    ```

    **Using API Method:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableEnterKeyToSubmit();
    commentElement.disableEnterKeyToSubmit();
    ```
  </Tab>
</Tabs>

#### enableDeleteOnBackspace

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

Default: `enabled`

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments deleteOnBackspace={false} />
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDeleteOnBackspace();
    commentElement.disableDeleteOnBackspace();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments delete-on-backspace="false"></velt-comments>
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDeleteOnBackspace();
    commentElement.disableDeleteOnBackspace();
    ```
  </Tab>
</Tabs>

# Uncategorised

#### excludeLocationIds

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const locationIds = ['location1', 'location2']; // list of location ids
    client.excludeLocationIds(locationIds);
    ```

    To reset it, you can pass an empty array:

    ```jsx
    client.excludeLocationIds([]);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const locationIds = ['location1', 'location2']; // list of location ids
    Velt.excludeLocationIds(locationIds);
    ```

    To reset it, you can pass an empty array:

    ```jsx
    Velt.excludeLocationIds([]);
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    To accept comments, set the `suggestionMode` attribute to `true`.

    ```js
    <VeltComments suggestionMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    To accept comments, set the `suggestion-mode` attribute to `true`.

    ```js
    <velt-comments suggestion-mode="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableSuggestionMode();
    commentElement.disableSuggestionMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableSuggestionMode();
    commentElement.disableSuggestionMode();
    ```
  </Tab>
</Tabs>

#### onCommentAccept / onCommentReject

To listen to comments that are Accepted or Rejected in Suggestion mode, pass callbacks to the `onCommentAccept` and onCommentReject\` event handlers.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments onCommentAccept={(event)=>yourMethod(event)}/>
    <VeltComments onCommentReject={(event)=>yourMethod(event)}/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const veltCommentsTag = document.querySelector('velt-comments');

    veltCommentsTag?.addEventListener('onCommentAccept', (event) => {
      console.log('*** onCommentAccept ***');
      console.log(event.detail);
    });

    veltCommentsTag?.addEventListener('onCommentReject', (event) => {
      console.log('*** onCommentReject ***');
      console.log(event.detail);
    });
    ```
  </Tab>
</Tabs>

Response:

```js
{
    "annotationId": "ANNOTATION_ID",
    "actionUser": {
        // user object
    },
    "actionType": "accept", // accept or reject
    "annotation": {
        // raw annotation object
    },
  	"replaceContentHtml": "HTML_FORMATTED_TEXT_TO_REPLACE", // optional
  	"replaceContentText": "PLAIN_TEXT_TO_REPLACE", // optional
}
```

# Inline Comments

#### sortData

*   Change the default sorting order of Comments in the Inline Comments Section.
*   Default: `none`

There are three options for sorting:

*   `asc`: Show comment annotations in ascending order of when they were last updated
*   `desc`: Show comment annotations in descending order of when they were last updated
*   `none`: Show comment annotations in the sequence they were added

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltInlineCommentsSection sortData="desc" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-inline-comments-section sort-data="desc"></velt-inline-comments-section>
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltInlineCommentsSection multiThread={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-inline-comments-section multi-thread="false">
    </velt-inline-comments-section>
    ```
  </Tab>
</Tabs>

# Toggle Comment Types

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

<Tabs>
  <Tab title="React / Next.js">
    To enable private comment mode, set the `privateCommentMode` attribute to `true`:

    ```html
    <VeltComments privateCommentMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    To enable private comment mode, set the `private-comment-mode` attribute to `true`:

    ```html
    <velt-comments private-comment-mode="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Methods:
API to enable/disable private comment mode:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    // To enable private comment mode
    commentElement.enablePrivateCommentMode();
    // To disable private comment mode
    commentElement.disablePrivateCommentMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    // To enable private comment mode
    commentElement.enablePrivateCommentMode();
    // To disable private comment mode
    commentElement.disablePrivateCommentMode();
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments areaComment={false} />
    ```

    **Using API Method:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableAreaComment();
    commentElement.disableAreaComment();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments area-comment="false"></velt-comments>
    ```

    Using API Method:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableAreaComment();
    commentElement.disableAreaComment();
    ```
  </Tab>
</Tabs>

#### enableInboxMode

<Info>For a complete setup guide for Inbox mode, [read here](/async-collaboration/comments/setup/inbox).</Info>

Whether Inbox Mode is enabled.

Default: `false`

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments inboxMode={true} />
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableInboxMode();
    commentElement.disableInboxMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments inbox-mode="true"></velt-comments> 
    ```

    **Using API:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableInboxMode();
    commentElement.disableInboxMode();
    ```
  </Tab>
</Tabs>

#### enablePopoverMode

<Info>For a complete setup guide for Popover mode, [read here](/async-collaboration/comments/setup/popover).</Info>

Whether Popover Mode is enabled.

Default: `false`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments popoverMode={true}/>
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enablePopoverMode();
    commentElement.disablePopoverMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments popover-mode="true"></velt-comments> 
    ```

    **Using API:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enablePopoverMode();
    commentElement.disablePopoverMode();
    ```
  </Tab>
</Tabs>

#### enableStreamMode

<Info>For a complete setup guide for Stream mode, [read here](/async-collaboration/comments/setup/stream).</Info>

Whether Stream Mode is enabled.

Default: `false`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments streamMode={true}/>
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableStreamMode();
    commentElement.disableStreamMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments stream-mode="true"></velt-comments> 
    ```

    **Using API:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableStreamMode();
    commentElement.disableStreamMode();
    ```
  </Tab>
</Tabs>

#### enableTextMode

<Info>For a complete setup guide for Text mode, [read here](/async-collaboration/comments/setup/text).</Info>

Whether Text Mode is enabled.

Default: `true`

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/text-comment.png)

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments textMode={true}/>
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableTextComments();
    commentElement.disableTextComments();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments text-mode="true"></velt-comments> 
    ```

    **Using API:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableTextComments();
    commentElement.disableTextComments();
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments inlineCommentMode={true}/>
    ```

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableInlineCommentMode();
    commentElement.disableInlineCommentMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments inline-comment-mode="true"></velt-comments> 
    ```

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableInlineCommentMode();
    commentElement.disableInlineCommentMode();
    ```
  </Tab>
</Tabs>

#### 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/overview).
*   Default: `false`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments multiThread={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comments multi-thread="true">
    </velt-comments>
    ```
  </Tab>
</Tabs>

# Priority

#### enablePriority

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/priority-default.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments priority={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments priority="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enablePriority();
    commentElement.disablePriority();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enablePriority();
    commentElement.disablePriority();
    ```
  </Tab>
</Tabs>

#### setCustomPriority

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/custom-priority.png)

<Tabs>
  <Tab title="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

    <VeltComments customPriority={[
      {
        "id": "low",
        "name": "Low",
        "color": "red",
        "lightColor": "pink",
      },
    ]}/>
    ```
  </Tab>

  <Tab title="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
    <velt-comments custom-priority='[
      {
        "id": "low",
        "name": "Low",
        "color": "red",
        "lightColor": "pink",
      }
    ]'></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

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

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.setCustomPriority([
      {
        "id": "low",
        "name": "Low",
        "color": "red",
        "lightColor": "pink",
      },
    ])
    ```
  </Tab>
</Tabs>

<Warning>
  Make sure to have at least 2 categories set.
</Warning>

# User

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

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments moderatorMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments moderator-mode="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableModeratorMode();
    commentElement.disableModeratorMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableModeratorMode();
    commentElement.disableModeratorMode();
    ```
  </Tab>
</Tabs>

#### enableResolveStatusAccessAdminOnly

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

<Tabs>
  <Tab title="React / Next.js">
    **Using props:**

    ```jsx
    <VeltComments resolveStatusAccessAdminOnly={true} />
    ```

    **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();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using props:**

    ```html
    <velt-comments resolve-status-access-admin-only="true"></velt-comments>
    ```

    **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();
    ```
  </Tab>
</Tabs>

#### enableSignInButton

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/sign-in-button.png)

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.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments signInButton={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments sign-in-button="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableSignInButton();
    commentElement.disableSignInButton();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableSignInButton();
    commentElement.disableSignInButton();
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments onSignIn={() => yourSignInMethod()} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const veltCommentsTag = document.querySelector('velt-comments');

    veltCommentsTag?.addEventListener('onSignIn', (event) => {
      console.log('*** onCommentSignIn ***');
      console.log(event.detail);
    });
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments shortUserName={false} />
    ```

    **Using API:**

    ```javascript
    const commentElement = client.getCommentElement();
    commentElement.enableShortUserName();
    commentElement.disableShortUserName();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments short-user-name="false"></velt-comments>
    ```

    **Using API:**

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.enableShortUserName();
    commentElement.disableShortUserName();
    ```
  </Tab>
</Tabs>

# Seen By

#### enableSeenByUsers

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

Default: `true`

<Tabs>
  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments seenByUsers={false} />
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableSeenByUsers();
    commentElement.disableSeenByUsers();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```html
    <velt-comments seen-by-users="false"></velt-comments>
    ```

    **Using API:**

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.enableSeenByUsers();
    commentElement.disableSeenByUsers();
    ```
  </Tab>
</Tabs>

#### 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`.

<Frame>
  ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/unread-compare.png)
</Frame>

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments unreadIndicatorMode={"verbose"} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments unread-indicator-mode="verbose"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.setUnreadIndicatorMode("verbose"); // use badge with text UNREAD
    commentElement.setUnreadIndicatorMode("minimal"); // use small red dot indicator
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.setUnreadIndicatorMode("verbose"); // use badge with text UNREAD
    commentElement.setUnreadIndicatorMode("minimal"); // use small red dot indicator
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltComments dialogOnTargetElementClick={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comments dialog-on-hover="true"></velt-comments>
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDialogOnTargetElementClick();
    commentElement.disableDialogOnTargetElementClick();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDialogOnTargetElementClick();
    commentElement.disableDialogOnTargetElementClick();
    ```
  </Tab>
</Tabs>

#### enablePopoverTriangleComponent

Whether the popover triangle appears when Popover Mode is enabled.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltComments popoverTriangleComponent={true}/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comments popover-triangle-component="true"></velt-comments> 
    ```
  </Tab>
</Tabs>

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enablePopoverTriangleComponent();
    commentElement.disablePopoverTriangleComponent();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enablePopoverTriangleComponent();
    commentElement.disablePopoverTriangleComponent();
    ```
  </Tab>
</Tabs>

# Comment Bubble

#### commentCountType

Whether to show unread or total comment replies count on Comment Bubble Component.

`Default: 'total'`

<Frame>
  ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-bubble.png)
</Frame>

<Tabs>
  <Tab title="React / Next.js">
    `commentCountType`: This prop allows you to decide which count to display.

    *   `total`: Shows the total number of replies. (default)
    *   `unread`: Shows the number of unread replies.

    ```jsx
    <VeltCommentBubble commentCountType={"unread"} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    `comment-count-type`: This prop allows you to decide which count to display.

    *   `total`: Shows the total number of replies. (default)
    *   `unread`: Shows the number of unread replies.

    ```jsx
    <velt-comment-bubble comment-count-type="unread">
    </velt-comment-bubble>
    ```
  </Tab>
</Tabs>

# 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'`

<Tabs>
  <Tab title="React / Next.js with Hooks">
    **Using Props:**

    ```jsx
    <VeltComments bubbleOnPin={true} />
    ```

    **Using API Method:**

    ```jsx
    const commentElement = useCommentUtils();
    commentElement.enableBubbleOnPin();
    commentElement.disableBubbleOnPin();
    ```
  </Tab>

  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments bubbleOnPin={true} />
    ```

    **Using API Method:**

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableBubbleOnPin();
    commentElement.disableBubbleOnPin();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments bubble-on-pin="true">
    </velt-comments>
    ```

    **Using API Method:**

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableBubbleOnPin();
    commentElement.disableBubbleOnPin();
    ```
  </Tab>
</Tabs>

#### enableBubbleOnPinHover

Show a Comment Bubble when user hovers on the Comment Pin vs clicks on it.

`Default: 'true'`

<Tabs>
  <Tab title="React / Next.js with Hooks">
    **Using Props:**

    ```jsx
    <VeltComments bubbleOnPin={true} bubbleOnPinHover={false} />
    ```

    **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();
    ```
  </Tab>

  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments bubbleOnPin={true} bubbleOnPinHover={false} />
    ```

    **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();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using Props:**

    ```jsx
    <velt-comments bubble-on-pin="true" bubble-on-pin-hover="false"></velt-comments>
    ```

    **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();
    ```
  </Tab>
</Tabs>

# Video Timeline Comments

#### offset

*   Allows comment bubbles to be positioned relative to both parent and child video clips by specifying an offset value.
*   Default: `0`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentPlayerTimeline offset={10} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-player-timeline offset="10"></velt-comment-player-timeline>
    ```
  </Tab>
</Tabs>


# Comments Notifications

There are several options to send notifications to your users.

<CardGroup cols={3}>
  <Card title="In-app notifications" href="/async-collaboration/notifications/overview" icon="bell" color="#FAA356" iconType="light">
    Add notifications component within your app.
  </Card>

  <Card title="Email notifications" href="/notifications/email/overview" icon="envelope" color="#FAA356" iconType="light">
    Send email notifications to your users.
  </Card>

  <Card title="Webhooks" href="/webhooks/overview" icon="webhook" color="#FAA356" iconType="light">
    Send notifications to other channels like Slack.
  </Card>
</CardGroup>


# Comments

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.

<Tabs>
  <Tab title="Freestyle">
    With `Freestyle` comments, you can pin `Comments` on any elements on the page or draw area comments.

    [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comments\&type=freestyle)

    <Frame>
      <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comments&type=freestyle" allow="camera; microphone" scrolling="no" frameBorder="0" height="500px" className="w-full" />
    </Frame>
  </Tab>

  <Tab title="Popover">
    With `Popover` comments, you can add `Comments` on table cells, like in Google Sheets.

    [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comments\&type=popover)

    <Frame>
      <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comments&type=popover" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="500px" />
    </Frame>
  </Tab>

  <Tab title="Stream">
    With `Stream` mode, your `Comments` will appear in a column on the right side.

    [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comments\&type=stream)

    <Frame>
      <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comments&type=stream" allow="camera; microphone" frameBorder="0" height="500px" className="w-full" />
    </Frame>
  </Tab>

  <Tab title="Text">
    With `Text` comments, you can leave `Comments` as text highlights.

    [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comments\&type=text)

    <Frame>
      <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comments&type=text" allow="camera; microphone" scrolling="no" frameBorder="0" height="500px" className="w-full" />
    </Frame>
  </Tab>

  <Tab title="Inline">
    With `Inline` comments, you can add a more traditional style of comments.

    [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comments\&type=inline)

    <Frame>
      <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comments&type=inline" allow="camera; microphone" scrolling="no" frameBorder="0" height="500px" className="w-full" />
    </Frame>
  </Tab>

  <Tab title="Inbox">
    With `Inbox` mode, your focused comments appear in a sidebar on the right.

    [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comments\&type=inbox)

    <Frame>
      <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comments&type=inbox" allow="camera; microphone" scrolling="no" frameBorder="0" height="500px" className="w-full" />
    </Frame>
  </Tab>

  <Tab title="Page">
    With `Page` comments, you can leave `Comments` at the page level.

    [Open in larger window](https://docs-mini-demo.vercel.app/comments-page-mode)

    <Frame>
      <iframe src="https://docs-mini-demo.vercel.app/comments-page-mode" allow="camera; microphone" scrolling="no" frameBorder="0" height="500px" className="w-full" />
    </Frame>
  </Tab>

  <Tab title="Chart">
    With `Chart` comments, you can leave `Comments` on popular charting libraries.

    {/* [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=nivo-charts) */}

    [Open in larger window](https://velt-chart-js-demo.vercel.app)

    <Frame>
      {/* <iframe
        src="https://landing-page-demo-velt.vercel.app/?feature=nivo-charts"
        allow="camera; microphone"
        scrolling="no"
        frameBorder="0"
        className="w-full"
        height="700px"
      ></iframe> */}

      <iframe src="https://velt-chart-js-demo.vercel.app" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
    </Frame>
  </Tab>

  <Tab title="Video">
    With `Video` comments, you can leave frame by frame `Comments` on videos.

    [Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=video-player)

    <Frame>
      <iframe src="https://landing-page-demo-velt.vercel.app/?feature=video-player" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="510px" />
    </Frame>
  </Tab>

  <Tab title="Lottie">
    With `Lottie` comments, you can leave frame by frame `Comments` on Lottie animations.

    [Open in larger window](https://lottiefiles-velt-integration-2.web.app/)

    <Frame>
      <iframe src="https://lottiefiles-velt-integration-2.web.app/" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
    </Frame>
  </Tab>
</Tabs>

There are several customizable components that work as part of the `Comments` feature set.

<Tabs>
  <Tab title="Comment Dialog">
    <Frame>
      ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-1.png)
    </Frame>
  </Tab>

  <Tab title="Comment Pin">
    <Frame>
      ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-pin-1.png)
    </Frame>
  </Tab>

  <Tab title="Text Comment Tool">
    <Frame>
      ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-text-comment-1.png)
    </Frame>
  </Tab>

  <Tab title="Comment Tool">
    <Frame>
      ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-tool-1.png)
    </Frame>
  </Tab>
</Tabs>


# ChartJS Comments Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/velt-chartjs-barchart.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Components from Chart.js">
        ```jsx
        import { Chart as ChartJS, BarElement } from 'chart.js';
        import { Bar } from 'react-chartjs-2'
        ```
      </Step>

      <Step title="Import Comments Components and Hooks from Velt">
        *   Add `VeltComments` to the root of your app. This component is required to render comments in your app.
        *   Add the `VeltCommentTool` component wherever you want to show the comment tool button. Clicking on it initiates comment mode & changes your mouse cursor to a comment pin.
            ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        ```jsx
        import { useCommentModeState, VeltCommentPin, VeltCommentTool, VeltComments } from '@veltdev/react';
        ```
      </Step>

      <Step title="Create a ref for the ChartJS component">
        *   Create a `ref` and pass it into the `ref` property of the `ChartJS` component.

        ```jsx
        const chartRef = useRef(null);

        <Bar data={data} options={options} ref={chartRef} />
        ```
      </Step>

      <Step title="Add a container div for the ChartJS component">
        1.  Apply `position: relative` style to the div. This ensures accurate positioning of Velt Comment Pins.
        2.  Set `data-velt-manual-comment-container` to `true`. This:

        *   informs Velt which div to use for positioning
        *   disables Velt's automatic comment positioning system within this div, allowing for manual positioning of comment pins

        3.  Give a unique ID to the chart to scope comments to the specific chart, isolating them from other charts.

        ```jsx
        const chartId = 'dataAnalyticsChart'; // Unique ID for the chart
        ```

        ```jsx
        return (
          <div style={{ position: 'relative' }}
            onClick={handleChartClick}
            data-velt-manual-comment-container="true">

            <Bar data={data} options={options} ref={chartRef} />
          </div>
        );
        ```
      </Step>

      <Step title="Add a Comment when the user clicks on the chart">
        1.  Handle chart click to find nearest data point and add a comment. *(Check `handleChartClick() method` on the right)*
        2.  Create `context` object which contains the information about the series, x-axis value, y-axis value, chartId and anything else that's relevant. This will be used when rendering the comment pin. *(Check `handleChartClick() method` on the right)*
        3.  Add comment with the `context` data. *(Check `addManualComment() method` on the right)*

        *   Only add a comment if the Velt `commentModeState` is true and the Velt `client` is available.

        {/* TODO: Create a hook for adding manual comments */}
      </Step>

      <Step title="Render the Velt Comment Pins and set its position">
        1.  Get all comment annotations.
        2.  Loop through it and render the comment pin.
        3.  Use the `context` data in `CommentAnnotation`, to set the position of the comment pin. *(Check `showCommentPin() method` on the right)*

        ```jsx
        const commentAnnotations = useCommentAnnotations(); // Get Velt comment annotations
        const [chartCommentAnnotations, setChartCommentAnnotations] = React.useState([]); // Store annotations for this chart

        useEffect(() => {
          // Filter and store comments for the current chart, using unique chart ID
          const chartCommentAnnotations = commentAnnotations?.filter((comment) => comment.context?.chartId === chartId); 
          setChartCommentAnnotations(chartCommentAnnotations as any || []);
        }, [commentAnnotations]);

        return (
            ... {/* Rest of the container code. */}

            {/* Loop through comment annotations and render the comment pin. */}
            {chartCommentAnnotations.map((comment, index) => showCommentPin(comment))}

            ... {/* Rest of the container code. */}
        );
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML (coming soon)">
    Coming Soon
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import React, { useEffect, useRef, useMemo } from 'react';
  import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, BarElement, Title, Tooltip, Legend, Filler,} from 'chart.js';
  import { Bar } from 'react-chartjs-2';
  import { useVeltClient, useCommentAnnotations, useCommentModeState, VeltCommentPin } from '@veltdev/react';

  // Register the necessary Chart.js components
  ChartJS.register(CategoryScale, LinearScale, PointElement, BarElement, Title, Tooltip, Legend, Filler);

  // Define the data for the chart
  const scores = [6, 5, 5, 5, 3, 4, 6, 4, 5];
  const labels = [100, 200, 300, 400, 500, 600, 700];

  // Set the options for the chart
  const options: any = {
  // your chart options
  };

  const BarChart = () => {
    const chartId = 'dataAnalyticsChart'; // Unique ID for the chart
    const chartRef = useRef(null); // Reference to the chart instance
    const { client } = useVeltClient(); // Get Velt client
    const commentModeState = useCommentModeState(); // Get Velt comment mode state
    const commentAnnotations = useCommentAnnotations(); // Get Velt comment annotations
    const [chartCommentAnnotations, setChartCommentAnnotations] = React.useState([]); // State for chart comments

    // Update chart comments when annotations change
    useEffect(() => {
      // Filter comments for the current chart, using unique chart ID
      const chartCommentAnnotations = commentAnnotations?.filter((comment) => comment.context?.chartId === chartId); 
      setChartCommentAnnotations(chartCommentAnnotations as any || []);
    }, [commentAnnotations]);

    // Handle chart clicks to find nearest data point and add a comment
    const handleChartClick = (event: any) => {
      const chart: any = chartRef.current;
      if (chart) {
        // Get the nearest element to the click event
        const elements = chart.getElementsAtEventForMode(event.nativeEvent, 'nearest', { intersect: true }, false);
        if (elements.length > 0) {
          const element = elements[0];
          const datasetIndex = element.datasetIndex;
          const index = element.index;
          const dataset = chart.data.datasets[datasetIndex];
          const xValue = chart.data.labels[index];
          const yValue = dataset.data[index];
          const context = { seriesId: dataset.label, xValue, yValue, chartId };
          addManualComment(context); // Add a comment at the nearest data point with the context data
        }
      }
    };

    // Add a manual comment to the chart
    const addManualComment = (context: any) => {
      try {
        if (client && commentModeState) {
          const commentElement = client.getCommentElement();
          commentElement.addManualComment({ context }); // Add a Velt comment
        }
      } catch (error) {
        console.error('Error adding manual comment', error);
      }
    };

    // Find the exact point on the chart to place a comment pin
    const findPoint = (seriesId: any, xValue: any, yValue: any) => {
      const chart: any = chartRef.current;
      if (chart) {
        const dataset = chart.data.datasets.find((dataset: any) => dataset.label === seriesId);
        const index = chart.data.labels.indexOf(xValue);
        if (dataset && index !== -1) {
          const yValueInDataset = dataset.data[index];
          if (yValueInDataset === yValue) {
            return { x: chart.scales.x.getPixelForValue(index), y: chart.scales.y.getPixelForValue(yValue) }; // Set the x, y position for the comment pin
          }
        }
      }
      return null;
    };

    // Show the comment pin on the chart at the specified point
    const showCommentPin = (commentAnnotation: any) => {
      const context = commentAnnotation.context || {};
      const point = findPoint(context.seriesId, context.xValue, context.yValue);
      if (point) {
        const { x, y } = point;
        return (
          <div
            key={commentAnnotation.annotationId}
            style={{
              left: `${x}px`,
              top: `${y}px`,
              position: 'absolute',
              transform: 'translate(0%, -100%)',
              zIndex: 1000,
            }}
          >
            <VeltCommentPin annotationId={commentAnnotation.annotationId} /> {/* Velt comment pin component */}
          </div>
        );
      }
      return null;
    };

    // Memoize the chart data
    const data = useMemo(() => {
      return {
        datasets: [
          {
            label: 'Mis datos',
            tension: 0.3,
            data: scores,
            borderColor: 'rgb(75, 192, 192)',
            backgroundColor: 'rgba(75, 192, 192, 0.3)',
          },
        ],
        labels,
      };
    }, []);

    return (
      <div className="dashlet-card">
        <div className="dashlet-card-header">Bar Chart With Comments</div>
        {/* Keep the parent div as relative, as comment pin will be placed with absolute position */}
        {/* Set "data-velt-manual-comment-container" to true, so that comment pin will know which div to consider while positioning */}
        <div style={{ position: 'relative' }} onClick={handleChartClick} data-velt-manual-comment-container="true"> 
          <Bar data={data} options={options} ref={chartRef} /> {/* Render the Bar chart */}
          {chartCommentAnnotations.map((comment, index) => showCommentPin(comment))} {/* Show all comment pins */}
        </div>
      </div>
    );
  };

  export default BarChart;
  ```
</RequestExample>


# Custom Charts Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/velt-chartjs-barchart.gif)

<Info>Here we have used ChartJS as an example library, you can follow the approach for any other charting library</Info>

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Components from your Charts Library">
        ```jsx
        import { Chart as ChartJS, BarElement } from 'chart.js';
        import { Bar } from 'react-chartjs-2'
        ```
      </Step>

      <Step title="Import Comments Components and Hooks from Velt">
        *   Add `VeltComments` to the root of your app. This component is required to render comments in your app.
        *   Add the `VeltCommentTool` component wherever you want to show the comment tool button. Clicking on it initiates comment mode & changes your mouse cursor to a comment pin.
            ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        ```jsx
        import { useCommentModeState, VeltCommentPin, VeltCommentTool, VeltComments } from '@veltdev/react';
        ```
      </Step>

      <Step title="Create a ref for the Chart component">
        *   Create a `ref` and pass it into the `ref` property of the `ChartJS` component.

        ```jsx
        const chartRef = useRef(null);

        <Bar data={data} options={options} ref={chartRef} />
        ```
      </Step>

      <Step title="Add a container div for the Chart component">
        1.  Apply `position: relative` style to the div. This ensures accurate positioning of Velt Comment Pins.
        2.  Set `data-velt-manual-comment-container` to `true`. This:

        *   informs Velt which div to use for positioning
        *   disables Velt's automatic comment positioning system within this div, allowing for manual positioning of comment pins

        3.  Give a unique ID to the chart to scope comments to the specific chart, isolating them from other charts.

        ```jsx
        const chartId = 'dataAnalyticsChart'; // Unique ID for the chart
        ```

        ```jsx
        return (
          <div style={{ position: 'relative' }}
            onClick={handleChartClick}
            data-velt-manual-comment-container="true">

            <Bar data={data} options={options} ref={chartRef} />
          </div>
        );
        ```
      </Step>

      <Step title="Add a Comment when the user clicks on the chart">
        1.  Handle chart click to find nearest data point and add a comment. *(Check `handleChartClick() method` on the right)*
        2.  Create `context` object which contains the information about the series, x-axis value, y-axis value, chartId and anything else that's relevant. This will be used when rendering the comment pin. *(Check `handleChartClick() method` on the right)*
        3.  Add comment with the `context` data. *(Check `addManualComment() method` on the right)*

        *   Only add a comment if the Velt `commentModeState` is true and the Velt `client` is available.

        {/* TODO: Create a hook for adding manual comments */}
      </Step>

      <Step title="Render the Velt Comment Pins and set its position">
        1.  Get all comment annotations.
        2.  Loop through it and render the comment pin.
        3.  Use the `context` data in `CommentAnnotation`, to set the position of the comment pin. *(Check `showCommentPin() method` on the right)*

        ```jsx
        const commentAnnotations = useCommentAnnotations(); // Get Velt comment annotations
        const [chartCommentAnnotations, setChartCommentAnnotations] = React.useState([]); // Store annotations for this chart

        useEffect(() => {
          // Filter and store comments for the current chart, using unique chart ID
          const chartCommentAnnotations = commentAnnotations?.filter((comment) => comment.context?.chartId === chartId); 
          setChartCommentAnnotations(chartCommentAnnotations as any || []);
        }, [commentAnnotations]);

        return (
            ... {/* Rest of the container code. */}

            {/* Loop through comment annotations and render the comment pin. */}
            {chartCommentAnnotations.map((comment, index) => showCommentPin(comment))}

            ... {/* Rest of the container code. */}
        );
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML (coming soon)">
    Coming Soon
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import React, { useEffect, useRef, useMemo } from 'react';
  import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, BarElement, Title, Tooltip, Legend, Filler,} from 'chart.js';
  import { Bar } from 'react-chartjs-2';
  import { useVeltClient, useCommentAnnotations, useCommentModeState, VeltCommentPin } from '@veltdev/react';

  // Register the necessary Chart.js components
  ChartJS.register(CategoryScale, LinearScale, PointElement, BarElement, Title, Tooltip, Legend, Filler);

  // Define the data for the chart
  const scores = [6, 5, 5, 5, 3, 4, 6, 4, 5];
  const labels = [100, 200, 300, 400, 500, 600, 700];

  // Set the options for the chart
  const options: any = {
  // your chart options
  };

  const BarChart = () => {
    const chartId = 'dataAnalyticsChart'; // Unique ID for the chart
    const chartRef = useRef(null); // Reference to the chart instance
    const { client } = useVeltClient(); // Get Velt client
    const commentModeState = useCommentModeState(); // Get Velt comment mode state
    const commentAnnotations = useCommentAnnotations(); // Get Velt comment annotations
    const [chartCommentAnnotations, setChartCommentAnnotations] = React.useState([]); // State for chart comments

    // Update chart comments when annotations change
    useEffect(() => {
      // Filter comments for the current chart, using unique chart ID
      const chartCommentAnnotations = commentAnnotations?.filter((comment) => comment.context?.chartId === chartId); 
      setChartCommentAnnotations(chartCommentAnnotations as any || []);
    }, [commentAnnotations]);

    // Handle chart clicks to find nearest data point and add a comment
    const handleChartClick = (event: any) => {
      const chart: any = chartRef.current;
      if (chart) {
        // Get the nearest element to the click event
        const elements = chart.getElementsAtEventForMode(event.nativeEvent, 'nearest', { intersect: true }, false);
        if (elements.length > 0) {
          const element = elements[0];
          const datasetIndex = element.datasetIndex;
          const index = element.index;
          const dataset = chart.data.datasets[datasetIndex];
          const xValue = chart.data.labels[index];
          const yValue = dataset.data[index];
          const context = { seriesId: dataset.label, xValue, yValue, chartId };
          addManualComment(context); // Add a comment at the nearest data point with the context data
        }
      }
    };

    // Add a manual comment to the chart
    const addManualComment = (context: any) => {
      try {
        if (client && commentModeState) {
          const commentElement = client.getCommentElement();
          commentElement.addManualComment({ context }); // Add a Velt comment
        }
      } catch (error) {
        console.error('Error adding manual comment', error);
      }
    };

    // Find the exact point on the chart to place a comment pin
    const findPoint = (seriesId: any, xValue: any, yValue: any) => {
      const chart: any = chartRef.current;
      if (chart) {
        const dataset = chart.data.datasets.find((dataset: any) => dataset.label === seriesId);
        const index = chart.data.labels.indexOf(xValue);
        if (dataset && index !== -1) {
          const yValueInDataset = dataset.data[index];
          if (yValueInDataset === yValue) {
            return { x: chart.scales.x.getPixelForValue(index), y: chart.scales.y.getPixelForValue(yValue) }; // Set the x, y position for the comment pin
          }
        }
      }
      return null;
    };

    // Show the comment pin on the chart at the specified point
    const showCommentPin = (commentAnnotation: any) => {
      const context = commentAnnotation.context || {};
      const point = findPoint(context.seriesId, context.xValue, context.yValue);
      if (point) {
        const { x, y } = point;
        return (
          <div
            key={commentAnnotation.annotationId}
            style={{
              left: `${x}px`,
              top: `${y}px`,
              position: 'absolute',
              transform: 'translate(0%, -100%)',
              zIndex: 1000,
            }}
          >
            <VeltCommentPin annotationId={commentAnnotation.annotationId} /> {/* Velt comment pin component */}
          </div>
        );
      }
      return null;
    };

    // Memoize the chart data
    const data = useMemo(() => {
      return {
        datasets: [
          {
            label: 'Mis datos',
            tension: 0.3,
            data: scores,
            borderColor: 'rgb(75, 192, 192)',
            backgroundColor: 'rgba(75, 192, 192, 0.3)',
          },
        ],
        labels,
      };
    }, []);

    return (
      <div className="dashlet-card">
        <div className="dashlet-card-header">Bar Chart With Comments</div>
        {/* Keep the parent div as relative, as comment pin will be placed with absolute position */}
        {/* Set "data-velt-manual-comment-container" to true, so that comment pin will know which div to consider while positioning */}
        <div style={{ position: 'relative' }} onClick={handleChartClick} data-velt-manual-comment-container="true"> 
          <Bar data={data} options={options} ref={chartRef} /> {/* Render the Bar chart */}
          {chartCommentAnnotations.map((comment, index) => showCommentPin(comment))} {/* Show all comment pins */}
        </div>
      </div>
    );
  };

  export default BarChart;
  ```
</RequestExample>


# Highcharts Comments Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Charts-Comments.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import components from Highcharts">
        ```jsx
        import Highcharts from 'highcharts';
        import HighchartsReact from 'highcharts-react-official';
        ```
      </Step>

      {/* bar/column, line */}

      <Step title="Import Comment components from Velt">
        *   Add `VeltComments` once to the root of your app. This component is required to render comments in your app.

        ```jsx
        import { VeltHighChartComments, VeltComments } from '@veltdev/react';
        ```
      </Step>

      <Step title="Create a ref for the HighchartsReact component">
        *   Create a `ref` and pass it into the `ref` property of the `HighchartsReact` component.
        *   This ref object will be used by Velt to get the Chart data and add comment pin to it.

        ```jsx
        const chartComponentRef = useRef(null);

        <HighchartsReact
            highcharts={Highcharts}
            options={options}
            ref={chartComponentRef}
        />
        ```
      </Step>

      <Step title="Add a container div for the HighchartsReact component">
        *   Give it a `position: relative` style. This will help position the Velt Comment Pins accurately.

        ```jsx
        <div style={{ position: 'relative' }}>
            <HighchartsReact
                highcharts={Highcharts}
                options={options}
                ref={chartComponentRef}
            />
        </div>
        ```
      </Step>

      <Step title="Add VeltHighChartComments component in the same container">
        *   Conditionally render `VeltHighChartsComments` in the same container div as the `HighchartsReact` component.
        *   Set a unique `id` in the VeltHighChartsComments component to scope comments to the specific chart, isolating them from other charts.
        *   Pass the `chartComputedData` prop with the `ref` you created earlier.

        ```jsx
        <div style={{ position: 'relative' }}>
            <HighchartsReact
                highcharts={Highcharts}
                options={options}
                ref={chartComponentRef}
            />
            {
                chartComponentRef.current && <VeltHighChartComments id="HighChartsLineChartExample" chartComputedData={chartComponentRef.current} />
            }
        </div>
        ```
      </Step>

      <Step title="(Optional) Customize the Chart Metadata displayed in the Comment Dialog">
        *   Pass an array to the `dialogMetadataTemplate` prop in the VeltHighChartsComments component.
        *   This array determines the chart metadata displayed in the comment dialog, representing the data point (e.g., x-axis and y-axis values) on which the comment was added.
        *   Customize the order of the keys or remove unnecessary keys to control how the metadata is presented in the comment dialog.

        `Default: ['groupId', 'label', 'value']`

        For example:

        ```jsx
        <VeltHighChartComments
            id="HighChartsLineChartExample"
            chartComputedData={chartComputedData}
            dialogMetadataTemplate={['label', 'value', 'groupId']} />
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML (coming soon)">
    Coming Soon
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import React, { useEffect, useRef, useState } from 'react';
  import { VeltHighChartComments } from '@veltdev/react';
  import Highcharts from 'highcharts';
  import HighchartsReact from 'highcharts-react-official';

  function HighChartsLineChartExample() {

      const [data, setData] = useState(CHART_DATA);
      const chartComponentRef = useRef(null);
      const options = {
          // your chart options
      };

      return (
          <div style={{ position: 'relative' }}>
              <HighchartsReact
                  highcharts={Highcharts}
                  options={options}
                  ref={chartComponentRef}
              />
              {
                  chartComponentRef.current && <VeltHighChartComments id="HighChartsLineChartExample" chartComputedData={chartComponentRef.current as any} />
              }
          </div>
      );
  }

  ```
</RequestExample>


# NivoCharts Comments Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Charts-Comments.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import components from Nivo Charts">
        ```jsx
        import { ResponsiveLine } from '@nivo/line';
        ```
      </Step>

      <Step title="Import VeltNivoChartComments component from Velt">
        *   Add `VeltComments` once to the root of your app. This component is required to render comments in your app.

        ```jsx
        import { VeltNivoChartComments, VeltComments } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add a container div for the Nivo Chart component">
        *   Add a `nivo-chart-container` class to it. This will help us position the Velt Comment Pins accurately.

        ```jsx
        <div style={{ height: 400, width: '100%' }} className='nivo-chart-container'>
          <ResponsiveLine
            data={data}
            layers={[ 
                'grid', 'markers', 'axes', 'areas', 'crosshair',
                'lines', 'slices', 'legends', 'points',
            ]}
            />
        </div>
        ```
      </Step>

      <Step title="Add VeltNivoChartComments to the Nivo Chart component">
        *   Add a custom function as a layer inside your Nivo Chart component and return `VeltNivoChartComments` component.
        *   Set a unique `id` in the VeltNivoChartComments component to scope comments to the specific chart, isolating them from other charts.
        *   Pass the `chartComputedData` props to it.

        {/* bar, line, pie */}

        ```jsx
        <ResponsiveLine
          data={data}
          layers={[ 
            'grid', 'markers', 'axes', 'areas', 'crosshair',
            'lines', 'slices', 'legends', 'points',
            // Add this function with VeltNivoChartComments
            // component to allow Velt comments inside the Chart
            (chartComputedData) => {
                return (
                    <VeltNivoChartComments id="NivoLineChartExample" chartComputedData={chartComputedData} />
                )
            }
          ]}
        />
        ```
      </Step>

      <Step title="(Optional) Customize the Chart Metadata displayed in the Comment Dialog">
        *   Pass an array to the `dialogMetadataTemplate` prop in the VeltHighChartsComments component.
        *   This array determines the chart metadata displayed in the comment dialog, representing the data point (e.g., x-axis and y-axis values) on which the comment was added.
        *   Customize the order of the keys or remove unnecessary keys to control how the metadata is presented in the comment dialog.

        `Default: ['groupId', 'label', 'value']`

        For example:

        ```jsx
        <VeltNivoChartComments
          id="NivoLineChartExample"
          chartComputedData={chartComputedData}
          dialogMetadataTemplate={['label', 'value', 'groupId']} />
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML (coming soon)">
    Coming Soon
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { ResponsiveLine } from '@nivo/line';
  import { VeltNivoChartComments } from '@veltdev/react';
  import { useState } from 'react'

  function YourComponent() {
    const [data, setData] = useState(CHART_DATA);

    return (
      // add nivo-chart-container class to the parent element of your NivoChart
      <div style={{ height: 400, width: '100%' }} className='nivo-chart-container'>
          <ResponsiveLine
              data={data}
              layers={[ 
                  'grid', 'markers', 'axes', 'areas', 'crosshair',
                  'lines', 'slices', 'legends', 'points',
                  // Add this function with VeltNivoChartComments
                  // component to allow Velt comments inside Chart
                  (chartComputedData) => {
                      return (
                          <VeltNivoChartComments id="NivoLineChartExample" chartComputedData={chartComputedData} dialogMetadataTemplate={['label', 'value', 'groupId']} />
                      )
                  }
              ]}
          />
  	</div>
    )  
  }
  ```
</RequestExample>


# Freestyle Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Freestyle-Comment.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Comment components">
        Import the `VeltComments` component and the `VeltCommentTool` component.

        ```js
        import {
          VeltProvider,
          VeltComments,
          VeltCommentTool
        } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Comments component">
        Add the `VeltComments` component to the root of your app.

        This component is required to render comments in your app.

        ```js
        <VeltProvider apiKey="API_KEY">
          <VeltComments />
        </VeltProvider>
        ```
      </Step>

      <Step title="Add Comment Tool component">
        Add the `VeltCommentTool` component wherever you want to show the comment tool button.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        Clicking on it initiates comment mode & changes your mouse cursor to a comment pin. Now you can click anywhere on the document to attach comments to any elements.

        ```js
        <div className="toolbar">
          <VeltCommentTool />
        </div>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by opening the page with Velt components in your browser.

        Click on the `Comment Tool` and click anywhere on the page to add a comment.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/standard-comment.png)
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add Comment component">
        Add the comment component to your template. Try to put it as close to the root level of your `<body>`.

        This component is required to render comments in your app.

        ```html
        <body>
          <velt-comments></velt-comments>
        </body>
        ```
      </Step>

      <Step title="Add Comment Tool component">
        Add the `<velt-comment-tool>` component wherever you want to show the comment tool button.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        Clicking on it initiates comment mode & changes your mouse cursor to a comment pin. Now you can click anywhere on the document to attach comments to any elements.

        ```js
        <div class="toolbar">
          <velt-comment-tool></velt-comment-tool>
        </div>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by adding a comment.

        You should be able to leave comments using the `Comment Tool`.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/standard-comment.png)
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import {
    VeltProvider,
    VeltComments,
    VeltCommentTool
  } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">
        <VeltComments />

        <div className="toolbar">
          <VeltCommentTool />
        </div>
      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Comment documentation</title>
    </head>
    <body>
      <velt-comments></velt-comments>

      <div class="toolbar">
        <velt-comment-tool></velt-comment-tool>
      </div>
    </body>
  </html>
  ```
</RequestExample>


# Inbox Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Inbox-Comment.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Comment components">
        Import the `VeltComments` component and the `VeltCommentTool` component.

        ```js
        import {
          VeltProvider,
          VeltComments,
          VeltCommentTool
        } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Comment component with Inbox mode">
        Add the `VeltComments` component to the root of your app and mark the `inboxMode` property as true.

        This component is required to render comments in your app.

        This mode enable a more focused inbox style UI for each comment on the right side. Instead of showing a comment dialog box, it shows the given comment in a sidebar.

        You can combine this with Freestyle, Popover, or Text mode.

        ```js
        <VeltProvider apiKey="API_KEY">
          <VeltComments inboxMode={true}/>
        </VeltProvider>
        ```
      </Step>

      <Step title="Add Comment Tool component">
        Add the `VeltCommentTool` component wherever you want to show the comment tool button.

        Clicking on it initiates comment mode & changes your mouse cursor to a comment pin. Now you can click anywhere on the document to attach comments to any elements.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        ```jsx
        <div className="toolbar">
          <VeltCommentTool />
        </div>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by opening the page with Velt components in your browser.

        You should be able to leave a comment by selecting some text or using the `Comment Tool`.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add Comment component with Inbox mode">
        Add the comment component to your template. Try to put it as close to the root level of your `<body>`.

        Set the `inbox-mode` attribute to `true`.

        This component is required to render comments in your app.

        This mode enable a more focused inbox style UI for each comment on the right side. Instead of showing a comment dialog box, it shows the given comment in a sidebar.

        You can combine this with Freestyle, Popover, or Text mode.

        ```html
        <body>
          <velt-comments inbox-mode="true"></velt-comments>
        </body>
        ```
      </Step>

      <Step title="Add the Comment tool component">
        The comment tool allows you to add comments.

        When you click on the comment tool, it initiates comment mode. In Freestyle mode, you can attach comments to any elements on the page.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        ```html
        <div class="toolbar">
          <velt-comment-tool></velt-comment-tool>
        </div>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by opening the page with Velt components in your browser.

        You should be able to leave a comment by selecting some text or using the `Comment Tool`.
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { VeltProvider, VeltComments, VeltCommentTool } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">

        <VeltComments inboxMode={true} />

        <div className="toolbar">
          <VeltCommentTool />
        </div>

      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Comment documentation</title>
    </head>
    <body>
      <velt-comments inbox-mode="true"></velt-comments>
      <div class="toolbar">
        <velt-comment-tool></velt-comment-tool>
      </div>
    </body>
  </html>
  ```
</RequestExample>


# Inline Comments Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/inline-comment.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Comment components">
        Import the `VeltProvider`, `VeltComments`, and `VeltInlineCommentsSection` component.

        ```js
        import { VeltProvider, VeltComments, VeltInlineCommentsSection } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add VeltComments component">
        *   Add the `VeltComments` component to the root of your app where your `VeltProvider` is.
        *   This component is required to render comments in your app.

        ```js
        <VeltProvider apiKey="API_KEY">
          <VeltComments />
        </VeltProvider>
        ```
      </Step>

      <Step title="Add container to hold Inline Comments component">
        *   Create an element to hold your Inline Comments component, such as a `div` or `section`.
        *   Add a unique element `id` to it.
        *   (optional) Set the same id to the `data-velt-target-inline-comment-element-id` attribute.
            This is used in advanced scenarios, eg: This ensures that if you add a freestyle or text comment within this container, it will appear in inline comments component too.

        ```jsx
        <section id="container-id" data-velt-target-inline-comment-element-id="container-id">
        	<div>Your Article</div>
        </section>
        ```
      </Step>

      <Step title="Add VeltInlineCommentsSection component">
        *   Add `VeltInlineCommentsSection` component inside your container.
        *   Add `targetCommentElementId` property to the Velt Inline Comments component. This needs to match the id you set to the container. This binds the Inline Comments component with the desired container.

        ```jsx
        <VeltInlineCommentsSection
          targetCommentElementId="container-id"
        />
        ```
      </Step>

      <Step title="(Optional) Make it single threaded or multithreaded">
        *   Default: `true`
        *   By default inline comment section is multithreaded.
        *   You can make it single threaded by setting `multiThread` attribute to `false`.

        ```jsx
        <VeltInlineCommentsSection multiThread={false} />
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add velt-comments component">
        *   Add the Velt Comments component to the root of your app.
        *   This component is required to render comments in your app.

        ```html
        <body>
          <velt-comments></velt-comments>
        </body>
        ```
      </Step>

      <Step title="Add container to hold Inline Comments component">
        *   Create an element to hold your Inline Comments component, such as a `div` or `section`.
        *   Add a unique element `id` to it.
        *   (optional) Set the same id to the `data-velt-target-inline-comment-element-id` attribute.
            This is used in advanced scenarios, eg: This ensures that if you add a freestyle or text comment within this container, it will appear in inline comments component too.

        ```html
        <section id="container-id" data-velt-target-inline-comment-element-id="container-id">
        	<div>Your Article</div>
        </section>
        ```
      </Step>

      <Step title="Add velt-inline-comments-section component">
        *   Add `velt-inline-comments-section` component inside your container.
        *   Add `target-comment-element-id` property to the Velt Inline Comments component. This needs to match the id you set to the container. This binds the Inline Comments component with the desired container.

        ```jsx
        <velt-inline-comments-section
        		target-comment-element-id="container-id"
        		shadow-dom="false"
        		dialog-variant="dialog-variant"
        		variant="inline-section-variant"
        		dark-mode="true"
        >
        </velt-inline-comments-section>
        ```
      </Step>

      <Step title="(Optional) Make it single threaded or multithreaded">
        *   Default: `true`
        *   By default inline comments are multithreaded.
        *   You can make it single threaded by setting `multi-thread` attribute to `false`.

        ```html
          <velt-inline-comments-section multi-thread="false">
          </velt-inline-comments-section>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { VeltProvider, VeltComments } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">

        <VeltComments />

        <section id="container-id" data-velt-target-inline-comment-element-id="container-id">
          <div>Your Article</div>

          <VeltInlineCommentsSection
            targetCommentElementId="container-id"
            shadowDom={false}
            dialogVariant="dialog-variant"
            variant="inline-section-variant"
            darkMode={true}
          />
        </section>


      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Comment documentation</title>
    </head>
    <body>
      <velt-comments></velt-comments>
      <section id="container-id" data-velt-target-inline-comment-element-id="container-id">
        <div>Your Article</div>

        <velt-inline-comments-section
          target-comment-element-id="container-id"
          shadow-dom="false"
          dialog-variant="dialog-variant"
          variant="inline-section-variant"
          dark-mode="true"
        >
        </velt-inline-comments-section>
      </section>

    </body>
  </html>
  ```
</RequestExample>


# Lottie Player Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Lottie-Comment.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Warning>Make sure you turn React strict mode off.</Warning>

    <Steps>
      <Step title="Add Velt Components in your app">
        ### a. Add the `VeltComments` component in the root of your app

        Add the `VeltComments` component to enable the Comment feature in your app.

        Enable the follow attributes to be `true`:

        *   `priority`: allows user to P0, P1, or P2 as priority. You can customize this list.
        *   `autoCategorize`: allows AI to categorize comment as Question, Feedback, Bug, Other. You can customize this list.
        *   `commentIndex`: shows a small icon showing index of the comment in order of creation.

        ```jsx
        <VeltComments priority={true} autoCategorize={true} commentIndex={true}/>
        ```

        ### b. Add the `VeltCommentTool` component wherever you want your render the comment tool.

        Note you can also provide your own button to this component.

        ```jsx
        <VeltCommentTool>
          <button slot="button">
            {/* your custom button (optional) */}
          </button>
        </VeltCommentTool>
        ```

        ### c. Place the `VeltCommentPlayerTimeline` component as a sibling to your video player.

        To show comment bubbles on your player seek bar, add the `<VeltCommentPlayerTimeline>` component as a sibling to your video player component.

        It will auto adjust to the same width as your video player.

        ```jsx
        <div>
          <YourVideoPlayer/>
          <VeltCommentPlayerTimeline/>
        </div>
        ```

        <Info>
          Right now we assume you have a maximum of one `<VeltCommentPlayerTimeline>` component and one sibling video player component per `documentID`
        </Info>

        <Warning>
          Ensure that the parent container of `<VeltCommentPlayerTimeline>` doesnt have CSS position value as 'static'.
        </Warning>

        ### d. Add the `<VeltCommentsSidebar>` component.

        (Optional) To embed the sidebar in your existing component, set `embedMode` prop as `true`.

        ```jsx
        <VeltCommentsSidebar embedMode={true}/>
        ```

        ### e. Add the `<VeltSidebarButton>` component.

        This will open or close the Comment Sidebar.
        Note you can also provide your own button to this component.

        ```jsx
        <VeltSidebarButton>
          <div className='sidebar-custom-btn'>
            {/* your custom button (optional) */}
          </div>
        </VeltSidebarButton>
        ```
      </Step>

      <Step title="Set the `totalMediaLength` on the `VeltCommentPlayerTimeline`">
        You can pass an integer to `totalMediaLength` using props to represent the total number of frames or seconds in the video:

        ```jsx
        <VeltCommentPlayerTimeline totalMediaLength={120} />
        ```

        Alternatively, you can set this using API method call. This is useful if you first need to grab the total frames from another method before setting it.

        ```jsx
        const commentElement = client.getCommentElement();
        commentElement.setTotalMediaLength(120);
        ```
      </Step>

      <Step title="Subscribe to when the Comment Tool is activated by the User.">
        Add an event handler on where you originally placed `<VeltCommentTool>` to handle `onCommentModeChange` events.

        Use this whenever the user clicks on the comment tool, to pause your player and set a new `Location` in the Velt SDK.

        Setting a `Location` in the Velt SDK ensures that the comments are tied to that particular media frame or timestamp.

        ```jsx

        <VeltCommentTool onCommentModeChange={(mode) => onCommentModeChange(mode)} />

        const onCommentModeChange = (mode) => {
            // mode will be `true` if the user has activated the comment tool
            // If the comment tool is active, pause the player and set the "location".
            if (mode) {
                // pause player
                // See step 8 below for details 
                setLocation()
            }
        });

        ```
      </Step>

      <Step title="Set Velt Location">
        You can pass in a key value pair object that represents the current state of your player. If you are using the `VeltCommentPlayerTimeline` component, ensure to set the current rounded frame or second in the special key `currentMediaPosition`.

        <Info>`currentMediaPosition` is a protected keyword that is used to arrange the comment bubbles on top of the video player timeline in the correct spot</Info>

        ```jsx
        const setLocation = (client) => {
            
            // set currentMediaPosition property on a Location object to represent the current frame
            let location = {
              currentMediaPosition : 120
            }
            //set the Location using the client
            client.setLocation(location)
            
        }
        ```
      </Step>

      <Step title="When the player is played, remove Velt `Location` to remove comments from the media.">
        Call `removeLocation()` when your player starts playing:

        ```jsx
        const removeLocation = () => {
            //remove the location, so the video player can play without comments appearing in frames
            client.removeLocation()
        }
        ```
      </Step>

      <Step title="Set your player's state when the user clicks on the comment.">
        Add the `onCommentClick` event handler on the `VeltCommentsSidebar` & `VeltCommentPlayerTimeline` components you added earlier.
        The event will give you back the `location` object that you had set earlier.

        You can use this object to update your player state and also update the SDK's `location` so that we can start rendering the comments associated with that `location`.

        ### a. Handle it on the `VeltCommentsSidebar`:

        ```jsx
        <VeltCommentsSidebar embedMode={true} onCommentClick={(event) => onCommentClick(event)} />

        const onCommentClick = (event) => {
            if (event) {
              // Get the location object from the event.
              const { location } = event;
              if (location) {
                  // Get the media position where the comment was added.
                  const { currentMediaPosition } = location;
                  if (currentMediaPosition) {
                      // Pause the player.

                      // Seek to the given comment media position.

                      // Set the Velt Location to the clicked comment location.
                      client.setLocation(location);
                  }
              }
          }
        }
        ```

        ### b. Handle it on the `VeltCommentPlayerTimeline`:

        ```jsx
        <VeltCommentPlayerTimeline onCommentClick={(event) => onTimelineCommentClick(event)} />

        const onTimelineCommentClick = (event) => {
          if (event) {
              // Get the location object from the event.
              const { location } = event;
              if (location) {
                  // Get the media position where the comment was added.
                  const { currentMediaPosition } = location;
                  if (currentMediaPosition) {
                      // Pause the player.

                      // Seek to the given comment media position.

                      // Set the Velt Location to the clicked comment location.
                      client.setLocation(location);
                  }
              }
          }
        }
        ```

        The clicked Comment data will be in the following format:

        | property          | type   | description                                                     |
        | ----------------- | ------ | --------------------------------------------------------------- |
        | `documentId`      | string | The document ID where the comment was added                     |
        | `location`        | object | The location where the comment was added                        |
        | `targetElementId` | string | The DOM ID of the target element on which the comment was added |
        | `context`         | Object | Any context data passed when the comment was added              |
      </Step>
    </Steps>

    # Additional Configurations

    ## Allow comments only on certain elements

    Provide a list of element DOM IDs where commenting should be allowed.
    Comments will be disabled for all other elements.

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.allowedElementIds(['lottiePlayerContainer']);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    <Steps>
      <Step title="Add Velt Components in your app">
        ### a. Add the `VeltComments` component in the root of your app

        Add the `VeltComments` component to enable the Comment feature in your app.

        Enable the follow attributes to be `true`:

        *   `priority`: allows user to P0, P1, or P2 as priority. You can customize this list.
        *   `auto-categorize`: allows AI to categorize comment as Question, Feedback, Bug, Other. You can customize this list.
        *   `comment-index`: shows a small icon showing index of the comment in order of creation.

        ```jsx
        <velt-comments priority="true" auto-categorize="true" commentIndex="true"></velt-comments>
        ```

        ### b. Add the `velt-comment-tool` component wherever you want your render the comment tool.

        Note you can also provide your own button to this component.

        ```jsx
        <velt-comment-tool>
          <button slot="button">
            <!-- your custom button (optional) -->
          </button>
        </velt-comment-tool>
        ```

        ### c. Place the `velt-commen-player-timeline` component as a sibling to your video player.

        To show comment bubbles on your player seek bar, add the `<velt-comment-player-timeline>` component as a sibling to your video player component.

        It will auto adjust to the same width as your video player.

        ```jsx
        <div>
          <your-video-player></your-video-player>
          <velt-comment-player-timeline></velt-comment-player-timeline>
        </div>
        ```

        <Info>
          Right now we assume you have a maximum of one `<velt-comment-player-timeline>` component and one sibling video player component per `documentID`
        </Info>

        <Warning>
          Ensure that the parent container of `<velt-comment-player-timeline>` doesnt have CSS position value as 'static'.
        </Warning>

        ### d. Add the `<velt-comments-sidebar>` component.

        (Optional) To embed the sidebar in your existing component, set `embed-mode` prop as `true`.

        ```jsx
        <velt-comments-sidebar embed-mode="true"></velt-comments-sidebar>
        ```

        ### e. Add the `<velt-sidebar-button>` component.

        This will open or close the Comment Sidebar.
        Note you can also provide your own button to this component.

        ```jsx
        <velt-sidebar-button>
          <div class='sidebar-custom-btn'>
            <!-- your custom button (optional) -->
          </div>
        </velt-sidebar-button>
        ```
      </Step>

      <Step title="Set the `total-media-length` on the `velt-comment-player-timeline`">
        You can pass an integer to `total-media-length` using props to represent the total number of frames or seconds in the video:

        ```jsx
        <velt-comment-player-timeline total-media-length="120"></velt-comment-player-timeline total-media-length="120">
        ```

        Alternatively, you can set this using API method call. This is useful if you first need to grab the total frames from another method before setting it.

        ```jsx
        const commentElement = Velt.getCommentElement();
        commentElement.setTotalMediaLength(120);
        ```
      </Step>

      <Step title="Subscribe to when the Comment Tool is activated by the User.">
        Add an event handler to handle `onCommentModeChange` events.

        Use this whenever the user clicks on the comment tool, to pause your player and set a new `Location` in the Velt SDK.

        Setting a `Location` in the Velt SDK ensures that the comments are tied to that particular media frame or timestamp.

        ```jsx
        const commentElement = Velt.getCommentElement();
        let subscription = commentElement.onCommentModeChange().subscribe((mode) => {
            // mode will be `true` if the user has activated the comment tool
            // If the comment tool is active, pause the player and set the "location".
            if (mode) {
                // pause player
                // See step 8 below for details 
                setLocation()
            }
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>

      <Step title="Set Velt Location">
        You can pass in a key value pair object that represents the current state of your player. If you are using the `velt-comment-player-timeline` component, ensure to set the current rounded frame or second in the special key `current-media-position`.

        <Info>`current-media-position` is a protected keyword that is used to arrange the comment bubbles on top of the video player timeline in the correct spot</Info>

        ```jsx
        const setLocation = (client) => {
            
            // set currentMediaPosition property on a Location object to represent the current frame
            let location = {
              currentMediaPosition : 120
            }
            //set the Location using the client
            Velt.setLocation(location)
            
        }
        ```
      </Step>

      <Step title="When the player is played, remove Velt `Location` to remove comments from the media.">
        Call `removeLocation()` when your player starts playing:

        ```jsx
        const removeLocation = () => {
            //remove the location, so the video player can play without comments appearing in frames
            Velt.removeLocation()
        }
        ```
      </Step>

      <Step title="Set your player's state when the user clicks on the comment.">
        Add the `onCommentClick` event handler on the `VeltCommentsSidebar` & `VeltCommentPlayerTimeline` components you added earlier.
        The event will give you back the `location` object that you had set earlier.
        You can use this object to update your player state and also update the SDK's `location` so that we can start rendering the comments associated with that `location`.

        ### a. Handle it on the `velt-comments-sidebar`:

        ```jsx
        <velt-comments-sidebar embed-mode="true"></velt-comments-sidebar>

        const onCommentClick = (event) => {
            if (event) {
              // Get the location object from the event.
              const { location } = event;
              if (location) {
                  // Get the media position where the comment was added.
                  const { currentMediaPosition } = location;
                  if (currentMediaPosition) {
                      // Pause the player.

                      // Seek to the given comment media position.

                      // Set the Velt Location to the clicked comment location.
                      client.setLocation(location);
                  }
              }
          }
        }

        const commentElement = Velt.getCommentElement();
        let subscription = commentElement.onSidebarButtonOnCommentDialogClick().subscribe((event) => onCommentClick(event));
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        ### b. Handle it on the `<velt-comment-player-timeline>`:

        ```html
        <velt-comment-player-timeline></velt-comment-player-timeline>
        <script>
            const playerTimelineElement = document.querySelector('velt-comment-player-timeline');
            if (playerTimelineElement) {
                playerTimelineElement.addEventListener('onCommentClick', (event) => {
                    console.log("onCommentClick: ", event.detail);
                });
            }
        </script>
        ```

        The clicked Comment data will be in the following format:

        | property          | type   | description                                                     |
        | ----------------- | ------ | --------------------------------------------------------------- |
        | `documentId`      | string | The document ID where the comment was added                     |
        | `location`        | object | The location where the comment was added                        |
        | `targetElementId` | string | The DOM ID of the target element on which the comment was added |
        | `context`         | Object | Any context data passed when the comment was added              |
      </Step>
    </Steps>

    # Additional Configurations

    ## Allow comments only on certain elements

    Provide a list of element DOM IDs where commenting should be allowed.
    Comments will be disabled for all other elements.

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.allowedElementIds(['lottiePlayerContainer']);
    ```
  </Tab>
</Tabs>


# Page Mode Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Page-Comments.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import CommentsSidebar Components">
        Import the Comments Sidebar Components.

        ```jsx
        import { 
          VeltProvider, 
          VeltCommentsSidebar, 
          VeltSidebarButton,
        } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Comments and Sidebar components">
        Add the `VeltComments` and `VeltCommentsSidebar` components to the root of your app.

        ```jsx
        <div>
          <VeltComments />
          <VeltCommentsSidebar />
        </div>
        ```
      </Step>

      <Step title="Enable Page Mode">
        Set the `pageMode` attribute to true on the `VeltCommentsSidebar` component.

        ```js App.js
          <VeltCommentsSidebar pageMode={true}/>
        ```
      </Step>

      <Step title="Add Sidebar button component">
        Add the Sidebar button to toggle the sidebar.

        ```jsx
        <div className="toolbar">
          <VeltSidebarButton />
        </div>
        ```
      </Step>

      <Step title="Test Page Mode">
        Test Page Mode out by opening the sidebar. You should be able to leave Page Mode comments at the bottom of the Comments Sidebar.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/page-comment.png)
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Place the `<velt-comments-sidebar>` component">
        Place the `<velt-comments-sidebar>` component at the root of your app.

        ```html
        <velt-comments-sidebar></velt-comments-sidebar>
        ```
      </Step>

      <Step title="Enable Page Mode">
        Enable Page Mode by setting the `page-mode` attribute to `true` on the `<velt-comments-sidebar>` component.

        ```html
        <velt-comments-sidebar page-mode="true"></velt-comments-sidebar>
        ```
      </Step>

      <Step title="Place the `<velt-sidebar-button>` component">
        Place the `<velt-sidebar-button>` component wherever you want the toggle button to appear.

        ```html
        <velt-sidebar-button></velt-sidebar-button>
        ```
      </Step>

      <Step title="Test Page Mode">
        Test Page Mode out by opening the sidebar. You should be able to leave Page Mode comments at the bottom of the Comments Sidebar.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/page-comment.png)
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { 
    VeltProvider, 
    VeltCommentsSidebar, 
    VeltSidebarButton,
  } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">
        <VeltComments /> {/* Add VeltComments to the root of your app provider */}
        <VeltCommentsSidebar pageMode={true} /> {/* Add VeltCommentsSidebar to the root of your app provider */}

        <div className="toolbar">
          <VeltSidebarButton /> {/* Add VeltCommentSideBarButton wherever you want it to appear */}
        </div>

      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");
        }
      </script>
    </head>
    <body>
      <velt-comments></velt-comments> <!-- add to the root of your app-->
      <velt-comments-sidebar page-mode="true"></velt-comments-sidebar> <!-- add to the root of your app -->
      <div class="toolbar"> <!-- a component representing a toolbar-->
        <velt-sidebar-button></velt-sidebar-button> <!-- add wherever you want it to appear -->
      </div>
      

    </body>
  </html>
  ```
</RequestExample>


# Popover Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Cell-Comment.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Comment components">
        Import the `VeltComments`, `VeltCommentTool`, and `VeltCommentBubble` components.

        ```js
        import {
          VeltProvider,
          VeltComments,
          VeltCommentTool,
          VeltCommentBubble
        } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Comments component with Popover mode">
        Add the `VeltComments` component to the root of your app and mark the `popoverMode` property as `true`.

        This component is required to render comments in your app.

        Popover mode means that comments can be attached to specific target elements. The UX pattern is very similar to commenting in Google Sheets.

        ```js
        <VeltProvider apiKey="API_KEY">
          <VeltComments popoverMode={true}/>
        </VeltProvider>
        ```
      </Step>

      <Step title="Add the Comment Tool component">
        There are two patterns to add the `Comment Tool` component with `Popover` comments:

        *   Add a `Comment Tool` next to each element you want to have `Popover` comments
        *   Have a single `Comment Tool` and use it to pin a `Popover `comment on a particular element

        ### a. Comment Tool next to each element

        In `Popover Mode`, you can add a `Comment Tool` near each cell or element you want to comment on.

        Add the `<VeltCommentTool>`component on each component where you want to enable commenting.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        For example, in a table you could add this tool to each cell and show it on hover or right click context menu.

        You must specify a target element ID which binds the tool to that element. When users click on the `Comment Tool`, it will attach a `Comment` to the target element.

        Once the `Comment` is saved, you will notice a triangle on the top right corner of the element indicating that a `Comment` is present on this element.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-comment-show.png)

        ```jsx
        <div className="table">
          <div className="cell" id="cell-id-1">
            <VeltCommentTool
              targetCommentElementId="cell-id-1"
            />
          </div>
          <div className="cell" id="cell-id-2">
            <VeltCommentTool
              targetCommentElementId="cell-id-2"
            />
          </div>
        </div>
        ```

        ### b. Single Comment Tool

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/freestyle-popover.gif)

        If you want to have a single `Comment Tool` in a single location such as the navigation bar, you can do so as well.

        To do this, add `data-velt-target-comment-element-id` as an attribute on each element you want to add comments on.

        Now, when you click on the `Comment Tool` and click on the target element, it will attach a `Popover` comment to the element.

        You will now notice that you can only add one `Comment Annotation` per element.

        <Warning>
          If you don't add the `data-velt-target-comment-element-id` attribute, you will be adding multiple `Comment Annotations` on the same element.
        </Warning>

        ```jsx
        <div>
          <VeltCommentTool />
          <div className="table">
            <div className="cell" data-velt-target-comment-element-id="cell-id-A" id="cell-id-A">

            </div>
            <div className="cell" data-velt-target-comment-element-id="cell-id-B" id="cell-id-B">

            </div>
          </div>
        </div>
        ```
      </Step>

      <Step title="Add the Comment Bubble component (optional)">
        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-bubble.png)

        This component accepts a target element ID & binds the comment annotation to it.

        It shows the total number of replies in the given comment annotation.
        You also have the option to choose whether to display the total number of replies or just the unread replies.

        This gives you a lot of flexibility as you can place this component anywhere and provides a more obvious affordance to your users.

        **Props:** `commentCountType`: This prop allows you to decide which count to display.

        *   `total`: Shows the total number of replies. (default)
        *   `unread`: Shows the number of unread replies.

        ```js
        <div className="table">
          <div className="cell" id="cell-id-1">
            <VeltCommentTool
              targetCommentElementId="cell-id-1"
            />
            <VeltCommentBubble
              commentCountType={"unread"}
              targetCommentElementId="cell-id-1"
            />
          </div>
          <div className="cell" id="cell-id-2">
            <VeltCommentTool
              targetCommentElementId="cell-id-2"
            />
            <VeltCommentBubble
              commentCountType={"unread"}
              targetCommentElementId="cell-id-2"
            />
          </div>
        </div>
        ```
      </Step>

      <Step title="Remove Popover Mode Triangle (optional)">
        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-comment-pin.png)

        You can choose to remove the triangle that appears in `Popover` mode.

        By default, the triangle is enabled.

        ```jsx
        <VeltComments popoverTriangleComponent={false}/>
        ```

        API Method:

        ```jsx
        const commentElement = client.getCommentElement();
        commentElement.enablePopoverTriangleComponent();
        commentElement.disablePopoverTriangleComponent();
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by opening the page with Velt components in your browser.

        Click on the `Comment Tool` and leave a comment on the target element.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-comment-pin.png)
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add Comment component with Popover mode">
        Add the comment component to your template. Try to put it as close to the root level of your `<body>`.

        This component is required to render comments in your app.

        ```html
        <body>
            <velt-comments popover-mode="true"></velt-comments>
        </body>
        ```
      </Step>

      <Step title="Add the Comment Tool component">
        There are two patterns to add the `Comment Tool` component with `Popover` comments:

        *   Add a `Comment Tool` next to each element you want to have `Popover` comments
        *   Have a single `Comment Tool` and use it to pin a `Popover `comment on a particular element

        ### Comment Tool next to each element

        In `Popover Mode`, you can add a `Comment Tool` near each cell or element you want to comment on.

        Add the `<velt-comment-tool>`component on each component where you want to enable commenting.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool.png)

        For example, in a table you could add this tool to each cell and show it on hover or right click context menu.

        You must specify a target element ID which binds the tool to that element. When users click on the `Comment Tool`, it will attach a `Comment` to the target element.

        Once the `Comment` is saved, you will notice a triangle on the top right corner of the element indicating that a `Comment` is present on this element.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-comment-show.png)

        ```html
        <div class="table">
          <div class="cell" id="cell-id-1">
            <velt-comment-tool
              target-comment-element-id="cell-id-1"
            ></velt-comment-tool>
          </div>
          <div class="cell" id="cell-id-2">
            <velt-comment-tool
              target-comment-element-id="cell-id-2"
            ></velt-comment-tool>
          </div>
        </div>
        ```

        ### Single Comment Tool

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/freestyle-popover.gif)

        If you want to have a single `Comment Tool` in a single location such as the navigation bar, you can do so as well.

        To do this, add `data-velt-target-comment-element-id` as an attribute on each element you want to add comments on.

        Now, when you click on the `Comment Tool` and click on the target element, it will attach a `Popover` comment to the element.

        You will now notice that you can only add one `Comment Annotation` per element.

        <Warning>
          If you don't add the `data-velt-target-comment-element-id` attribute, you will be adding multiple `Comment Annotations` on the same element.
        </Warning>

        ```jsx
        <div>
          <velt-comment-tool></velt-comment-tool>
          <div class="table">
            <div class="cell" data-velt-target-comment-element-id="cell-id-A" id="cell-id-A">

            </div>
            <div class="cell" data-velt-target-comment-element-id="cell-id-B" id="cell-id-B">

            </div>
          </div>
        </div>
        ```
      </Step>

      <Step title="Add the Comment Bubble component (optional)">
        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-bubble.png)

        This component accepts a target element ID & binds the comment annotation to it.

        It shows the total number of replies in the given comment annotation.
        You also have the option to choose whether to display the total number of replies or just the unread replies.

        This gives you a lot of flexibility as you can place this component anywhere and provides a more obvious affordance to your users.

        **Props:** `comment-count-type`: This prop allows you to decide which count to display.

        *   `total`: Shows the total number of replies. (default)
        *   `unread`: Shows the number of unread replies.

        ```html
        <div class="table">
          <div class="cell" id="cell-id-1">
            <velt-comment-tool
              target-comment-element-id="cell-id-1"
            ></velt-comment-tool>
            <velt-comment-bubble
              comment-count-type="unread"
              target-comment-element-id="cell-id-1"
            ><velt-comment-bubble>
          </div>
          <div class="cell" id="cell-id-2">
            <velt-comment-tool
              target-comment-element-id="cell-id-2"
            ></velt-comment-tool>
            <velt-comment-bubble
              comment-count-type="unread"
              target-comment-element-id="cell-id-2"
            ><velt-comment-bubble>
          </div>
        </div>
        ```
      </Step>

      <Step title="Remove Popover Mode Triangle (optional)">
        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-comment-pin.png)

        You can choose to remove the triangle that appears in `Popover` mode.

        By default, the triangle is enabled.

        ```jsx
        <velt-comments popover-triangle-component="false"></velt-comments>
        ```

        API Method:

        ```jsx
        const commentElement = client.getCommentElement();
        commentElement.enablePopoverTriangleComponent();
        commentElement.disablePopoverTriangleComponent();
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by adding a comment.

        You should be able to leave a comment on the target element using the `Comment Tool`.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/popover-comment-pin.png)
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import {
    VeltProvider,
    VeltComments,
    VeltCommentTool,
    VeltCommentBubble
  } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">
        <VeltComments popoverMode={true} popoverTriangleComponent={true} />


        {/* Comment Tool next to each element */}
        <div className="table">
          <div className="cell" id="cell-id-1">
            <VeltCommentTool
              targetCommentElementId="cell-id-1"
            />
          </div>
          <div className="cell" id="cell-id-2">
            <VeltCommentBubble
              targetCommentElementId="cell-id-2"
            />
          </div>
        </div>

        {/* Single Comment Tool */}
        <div>
          <VeltCommentTool/>
          <div className="table">
            <div className="cell" data-velt-target-comment-element-id="cell-id-A" id="cell-id-A">

            </div>
            <div className="cell" data-velt-target-comment-element-id="cell-id-B" id="cell-id-B">

            </div>
          </div>
        </div>

      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Comment documentation</title>
    </head>
    <body>
      <velt-comments popover-triangle-component="true"></velt-comments>


      <!-- Comment Tool next to each element -->
      <div class="table">
        <div class="cell" id="cell-id-1">
          <velt-comment-tool
            target-comment-element-id="cell-id-1"
          ></velt-comment-tool>
        </div>
        <div class="cell" id="cell-id-2">
          <velt-comment-bubble
            target-comment-element-id="cell-id-2"
          ></velt-comment-bubble>
        </div>
      </div>


      <!-- Single Comment Tool -->
      <div>
          <velt-comment-tool></velt-comment-tool>
          <div class="table">
            <div class="cell" data-velt-target-comment-element-id="cell-id-A" id="cell-id-A">

            </div>
            <div class="cell" data-velt-target-comment-element-id="cell-id-B" id="cell-id-B">

            </div>
          </div>
      </div>


    </body>
  </html>
  ```
</RequestExample>


# Stream Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/View-Stream-Comments.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Comment components">
        Import the `VeltComments` component.

        ```js
        import {
          VeltProvider,
          VeltComments,
        } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add `VeltComments` component with Stream mode">
        Add the `VeltComments` component inside a scrolling container. Make it a sibling to the element that contains the content you want to be commented.

        In the `VeltComments` component, mark the `streamMode` attribute as `true`.

        Also set the `streamViewContainerId` attribute to the id of the scrolling container.

        Stream mode renders all comment dialog boxes in a column on the right side similar to Google Docs. It works well with Text mode, which is enabled by default.

        Setting a reference to the container ID helps us position & scroll the comment stream as the user scrolls more robustly.

        ```js
        <VeltProvider apiKey="API_KEY">
          <div id="scrolling-container-id">
            //This element is scrollable
            <div className="target-content">
              //This element contains the content that you want to be commented.
            </div>
            <VeltComments
              streamMode={true}
              streamViewContainerId="scrolling-container-id"
            />
          </div>
        </VeltProvider>

        ```
      </Step>

      <Step title="Test Integration">
        Test it out by adding a comment.

        Select any text, a `Comment Tool` button will appear near the highlighted text.

        Click on it to add a comment and see the comment appear in the comment stream.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add the velt-comments component with Stream mode">
        Add the `<velt-comments>`  component inside a scrolling container. Make it a sibling to the element that contains the content you want to be commented.

        In the `<velt-comments>`  component, mark the `stream-mode` attribute as `true`.

        Also set the `stream-view-container-id` attribute to the id of the scrolling container.

        Stream mode renders all comment dialog boxes in a column on the right side similar to Google Docs. It works well with Text mode, which is enabled by default.

        Setting a reference to the container ID helps us position & scroll the comment stream as the user scrolls more robustly.

        ```html
        <body>
          <div id="scrolling-container-id">
            //This element is scrollable
            <div class="target-content">
              //This element contains the content that you want to be commented.
            </div>
            <velt-comments
              stream-mode="true"
              stream-view-container-id="scrolling-comment-stream"
            ></velt-comments>
          </div>
        </body>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by adding a comment.

        Select any text, a `Comment Tool` button will appear near the highlighted text.

        Click on it to add a comment and see the comment appear in the comment stream.
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { VeltProvider, VeltComments, VeltCommentTool } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">

        <div id="scrolling-container-id">

          //This element is scrollable
          <div className="target-content">
            //This element contains the content that you want to be commented.
          </div>

          <VeltComments
            streamMode={true}
            streamViewContainerId="scrolling-container-id"
          />

        </div>

      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Comment documentation</title>
    </head>
    <body>
      <div id="scrolling-container-id">
        //This element is scrollable
        <div class="target-content">
          //This element contains the content that you want to be commented.
        </div>
        <velt-comments
          stream-mode="true"
          stream-view-container-id="scrolling-comment-stream"
        ></velt-comments>
      </div>
    </body>
  </html>
  ```
</RequestExample>


# Text Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Text-Comments.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Comment components">
        Import the `VeltComments` component.

        ```js
        import { VeltProvider, VeltComments } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Comment component with Text mode">
        Add the `VeltComments` component to the root of your app.

        This component is required to render comments in your app.

        Text mode is enabled by default. To disable it, set the `textMode` attribute to `false`.

        Text mode allows users to select any text and attach comments to it similar to Google Docs.

        ```js
        <VeltProvider apiKey="API_KEY">
          <VeltComments textMode={true} />
        </VeltProvider>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by opening the page with Velt components in your browser.

        Select any text, a `Comment Tool` button will appear near the highlighted text. Click on it to add a comment.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/text-comment.png)
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add Comment component with Text mode">
        Add the comment component to your template. Try to put it as close to the root level of your `<body>`.

        This component is required to render comments in your app. Text mode allows users to attach comments to highlighted text.

        ```html
        <body>
          <velt-comments text-mode="true"></velt-comments>
        </body>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by opening the page with Velt components in your browser.

        Select any text, a `Comment Tool` button will appear near the highlighted text. Click on it to add a comment.

        ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/text-comment.png)
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { VeltProvider, VeltComments } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">

        <VeltComments textMode={true} />

      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Comment documentation</title>
    </head>
    <body>
      <velt-comments text-mode="true"></velt-comments>
    </body>
  </html>
  ```
</RequestExample>


# Tiptap Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/Add-Text-Comments.gif)

<Steps titleSize="h2">
  <Step title="Add Comment components">
    *   Add the `Velt Comments` component to the root of your app.
    *   This component is required to render comments in your app.
    *   Set the `text mode` prop to `false` to hide the default text comment tool.

    <Tabs>
      <Tab title="React / Next.js">
        ```js
        <VeltProvider apiKey="API_KEY">
          <VeltComments textMode={false} />
        </VeltProvider>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <body>
          <velt-comments text-mode="false"></velt-comments>
        </body>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Install the Velt Tiptap extension">
    ```bash
    npm i @veltdev/tiptap-velt-comments
    ```
  </Step>

  <Step title="Import and add the extension to your Tiptap editor">
    <Tabs>
      <Tab title="React / Next.js">
        ```js
        import { TiptapVeltComments } from '@veltdev/tiptap-velt-comments';

        const editor = new Editor({
          extensions: [
            TiptapVeltComments,
            // ... other extensions
          ],
        });
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        import { TiptapVeltComments } from '@veltdev/tiptap-velt-comments';

        const editor = new Editor({
          extensions: [
            TiptapVeltComments,
            // ... other extensions
          ],
        });
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add a button to add a comment in the context menu">
    *   Add a button that appears in the context menu of your Tiptap editor when the user selects text. Refer to the [Tiptap documentation](https://tiptap.dev/docs/editor/getting-started/style-editor/custom-menus) to learn more about custom menus.
    *   This button will be used to add a comment to the selected text.
  </Step>

  <Step title="Call `addTiptapVeltComment` to add a comment">
    *   Call this method to add a comment to selected text in the Tiptap editor. You can use this when the user clicks on the comment button in context menu or presses a keyboard shortcut.

    *   Args:
        *   `editor`: instance of the Tiptap editor.
        *   `tiptapVeltCommentConfig`: optional object to set the Comment Annotation's [custom metadata](/async-collaboration/comments/customize-behavior/custom-metadata).

    *   Example:
        <Tabs>
          <Tab title="React / Next.js">
            ```js
            import { addTiptapVeltComment } from '@veltdev/tiptap-velt-comments';

            const tiptapVeltCommentConfig = {
              context: {
                storyId: 'story-id',
                storyName: 'story-name',
              },
            };

            addTiptapVeltComment(editor, tiptapVeltCommentConfig);
            ```
          </Tab>

          <Tab title="Other Frameworks">
            ```js
            import { addTiptapVeltComment } from '@veltdev/tiptap-velt-comments';

            const tiptapVeltCommentConfig = {
              context: {
                storyId: 'story-id',
                storyName: 'story-name',
              },
            };

            addTiptapVeltComment(editor, tiptapVeltCommentConfig);
            ```
          </Tab>
        </Tabs>
  </Step>

  <Step title="Style the commented text">
    *   You can style the commented text by adding a CSS class to the `velt-comment-text` element.
    *   By using the `comment-available` attribute, you can apply styles only when the comment data has loaded.

    ```css
    velt-comment-text[comment-available="true"] {
      background-color: #ffff00;
    }
    ```
  </Step>
</Steps>


# Custom Video Player Setup

Use this guide to add collaboration into your own custom video player.

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/custom-video-player.gif)

<Steps>
  <Step title="Set up Velt Components in your app">
    You will be using the following components:

    *   `Velt Comments`: Renders comments on the DOM.
    *   `Velt Comment Tool`: Enables or disables adding comments.
    *   `Velt Reaction Tool`: Enables or disables adding reactions.
    *   `Velt Comment Player Timeline`: Adds comments bubble over your player seek bar.
    *   `Velt Comments Sidebar`: Adds a sidebar that shows all comments. Users can also search, filter & navigate to the comments from here.
    *   `Velt Sidebar Button`: Toggles the sidebar on/off.

    ### Add the `Velt Comments` component in the root of your app

    Add the `Velt Comments` component to the root of your app.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltComments />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comments></velt-comments>
        ```
      </Tab>
    </Tabs>

    ### Add the `Velt Comment Tool` component wherever you want your render the comment tool.

    Note you can also provide your own button to this component.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentTool>
          <button>
            {/* your custom button (optional) */}
          </button>
        </VeltCommentTool>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <velt-comment-tool>
          <button>
            <!-- your custom button (optional) -->
          </button>
        </velt-comment-tool>
        ```
      </Tab>
    </Tabs>

    ### Add the `Velt Reaction Tool` component wherever you want your render the reaction tool.

    *   Provide the video player ID on which you want the reactions to be added.
    *   Add an event handler to handle `onReactionToolClick` events.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltReactionTool videoPlayerId={videoPlayerId}
          onReactionToolClick={() => onReactionToolClick()}>
        </VeltReactionTool>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <div>
          <velt-reaction-tool video-player-id="videoPlayerId"></velt-reaction-tool>
        </div>
        ```

        ```js
        const reactionToolTag = document.querySelector('velt-reaction-tool');
        reactionToolTag.addEventListener('onReactionToolClick', (event) => {
          console.log('reaction tool clicked', event.detail);
        });
        ```
      </Tab>
    </Tabs>

    ### Place the `Velt Comment Player Timeline` component as a sibling to your video player.

    *   To show comment bubbles on your player seek bar, add the `Velt Comment Player Timeline` component as a sibling to your video player component.
    *   It will auto adjust to the same width as your video player.

    <Info>
      Right now we assume you have a maximum of one `velt comment player timeline` component and one sibling video player component per `documentID`
    </Info>

    <Warning>
      Ensure that the parent container of `velt comment player timeline` doesnt have CSS position value as 'static'.
    </Warning>

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <div>
          <YourVideoPlayer id="videoPlayerId"/>
          <VeltCommentPlayerTimeline videoPlayerId="videoPlayerId"/>
        </div>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <div>
          <your-video-player id="videoPlayerId"></your-video-player>
          <velt-comment-player-timeline video-player-id="videoPlayerId"></velt-comment-player-timeline>
        </div>
        ```
      </Tab>
    </Tabs>

    ### Add `id` to the video player or its parent element.

    *   If you don't have access to the raw `<video>` player, you can add an `id` to the parent element of the video player.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <div id="videoPlayerId">
          <YourVideoPlayer />
          <VeltCommentPlayerTimeline videoPlayerId="videoPlayerId"/>
        </div>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <div id="videoPlayerId">
          <your-video-player></your-video-player>
          <velt-comment-player-timeline video-player-id="videoPlayerId"></velt-comment-player-timeline>
        </div>
        ```
      </Tab>
    </Tabs>

    ### Add the `Velt Comments Sidebar` component.

    (Optional) To embed the sidebar in your existing component, set `embedMode` prop as `true`.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentsSidebar embedMode={true}/>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <velt-comments-sidebar embed-mode="true"></velt-comments-sidebar>
        ```
      </Tab>
    </Tabs>

    ### Add the `Velt Sidebar Button` component.

    This will open or close the Comment Sidebar.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltSidebarButton>
        </VeltSidebarButton>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <velt-sidebar-button>
        </velt-sidebar-button>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Set the `total media length` on the `Velt Comment Player Timeline`">
    You can pass an integer to `total media length` using props to represent the total number of frames or seconds in the video:

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentPlayerTimeline videoPlayerId="videoPlayerId" totalMediaLength={120} />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <velt-comment-player-timeline video-player-id="videoPlayerId" total-media-length="120"></velt-comment-player-timeline>
        ```
      </Tab>
    </Tabs>

    Alternatively, you can set this using API method call.
    This is useful if you first need to grab the total frames from another method before setting it.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        const commentElement = client.getCommentElement();
        commentElement.setTotalMediaLength(120);
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        const commentElement = Velt.getCommentElement();
        commentElement.setTotalMediaLength(120);
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Detect Comment Tool Activation and Set Media Location">
    *   Detect when the user activates the comment tool by adding an event handler to the `onCommentModeChange` event.
    *   Pause your player and set a new `Location` in the Velt SDK.
    *   This ensures that the comments are tied to that particular media frame or timestamp.
    *   You can pass in a key value pair object that represents the current state of your player.

    If you are using the `Velt Comment Player Timeline` component, ensure to set the current rounded frame or second in the special key `currentMediaPosition`.
    <Info>`currentMediaPosition` is a protected keyword that is used to arrange the comment bubbles on top of the video player timeline in the correct spot</Info>

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentTool onCommentModeChange={(mode) => onCommentModeChange(mode)} />

        const onCommentModeChange = (mode) => {
            // mode will be `true` if the user has activated the comment tool
            // If the comment tool is active, pause the player and set the "location".
            if (mode) {
                // pause player
                setLocation()
            }
        });

        const setLocation = (client) => {
            
            // set currentMediaPosition property on a Location object to represent the current frame
            let location = {
              currentMediaPosition : 120,
              videoPlayerId : "videoPlayerId"
            }
            //set the Location using the client
            client.setLocation(location)
            
        }
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        const commentElement = Velt.getCommentElement();
        let subscription = commentElement.onCommentModeChange().subscribe((mode) => {
            // mode will be `true` if the user has activated the comment tool
            // If the comment tool is active, pause the player and set the "location".
            if (mode) {
                // pause player
                setLocation()
            }
        });

        const setLocation = (client) => {
          // set currentMediaPosition property on a Location object to represent the current frame
          let location = {
            currentMediaPosition : 120,
            videoPlayerId : "videoPlayerId"
          }
          //set the Location using the client
          Velt.setLocation(location)
        }
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Detect Reaction Tool Activation and Set Media Location">
    *   Detect when the user activates the reaction tool by adding an event handler to the `onReactionToolClick` event.
    *   Pause your player and set a new `Location` in the Velt SDK.
    *   This ensures that the reactions are tied to that particular media frame or timestamp.
    *   You can pass in a key value pair object that represents the current state of your player.
        If you are using the `Velt Comment Player Timeline` component, ensure to set the current rounded frame or second in the special key `currentMediaPosition`.
        <Info>`currentMediaPosition` is a protected keyword that is used to arrange the comment bubbles on top of the video player timeline in the correct spot</Info>

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx

        <VeltReactionTool videoPlayerId={videoPlayerId}
          onReactionToolClick={() => onReactionToolClick()}>
        </VeltReactionTool>

        const onReactionToolClick = () => {
            // pause player
            setLocation()
        });

        const setLocation = () => {
            // set currentMediaPosition property on a Location object to represent the current frame
            let location = {
              currentMediaPosition : 120,
              videoPlayerId : "videoPlayerId"
            }
            //set the Location using the client
            client.setLocation(location)
            
        }
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <velt-reaction-tool video-player-id="videoPlayerId"></velt-reaction-tool>

        const reactionToolTag = document.querySelector('velt-reaction-tool');
        reactionToolTag.addEventListener('onReactionToolClick', (event) => {
            console.log('reaction tool clicked', event.detail);
        });
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="When the player is played, remove Velt `Location` to remove comments from the media.">
    Call `removeLocation()` when your player starts playing:

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        const removeLocation = () => {
            //remove the location, so the video player can play without comments appearing in frames
            client.removeLocation()
        }
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        const removeLocation = () => {
            //remove the location, so the video player can play without comments appearing in frames
            Velt.removeLocation()
        }
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Navigate to the comment's location in the player from the Sidebar or Timeline.">
    Add the `onCommentClick` event handler on the `Velt Comments Sidebar` & `Velt Comment Player Timeline` components you added earlier.
    The event will give you back the `location` object that you had set on the comment.

    Use this object to:

    *   update your player state
    *   update the SDK's `location` so the comments associated with that `location` are rendered.

    ### Handle click on the `Velt Comments Sidebar`:

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentsSidebar embedMode={true} onCommentClick={(event) => onCommentClick(event)} />

        const onCommentClick = (event) => {
            if (event) {
              // Get the location object from the event.
              const { location } = event;
              if (location) {
                  // Get the media position where the comment was added.
                  const { currentMediaPosition } = location;
                  if (currentMediaPosition) {
                      // Pause the player.

                      // Seek to the given comment media position.

                      // Set the Velt Location to the clicked comment location.
                      client.setLocation(location);
                  }
              }
          }
        }
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        const commentElement = document.querySelector('velt-comments-sidebar');
        commentElement.addEventListener('onCommentClick', onCommentClick);

        // event handler for when a comment is clicked on 
        const onCommentClick = (event) => {
          if (event) {
            // Get the location object from the event.
            const { location } = event;
            if (location) {
              // Get the media position where the comment was added.
              const { currentMediaPosition } = location;
              if (currentMediaPosition) {
                // Pause the player.

                // Seek to the given comment media position.

                // Set the Velt Location to the clicked comment location.
                client.setLocation(location);
              }
            }
          }
        };

        ```
      </Tab>
    </Tabs>

    ### Handle click on the `Velt Comment Player Timeline`:

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentPlayerTimeline videoPlayerId="videoPlayerId" onCommentClick={(event) => onTimelineCommentClick(event)} />

        const onTimelineCommentClick = (event) => {
          if (event) {
              // Get the location object from the event.
              const { location } = event;
              if (location) {
                  // Get the media position where the comment was added.
                  const { currentMediaPosition } = location;
                  if (currentMediaPosition) {
                      // Pause the player.

                      // Seek to the given comment media position.

                      // Set the Velt Location to the clicked comment location.
                      client.setLocation(location);
                  }
              }
          }
        }
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        const playerTimelineElement = document.querySelector('velt-comment-player-timeline');
        if (playerTimelineElement) {
          playerTimelineElement.addEventListener('onCommentClick', (event) => {
            console.log("onCommentClick: ", event.detail);
          });
        }
        ```
      </Tab>
    </Tabs>

    The clicked Comment data will be in the following format:

    | property          | type   | description                                                     |
    | ----------------- | ------ | --------------------------------------------------------------- |
    | `documentId`      | string | The document ID where the comment was added                     |
    | `location`        | object | The location where the comment was added                        |
    | `targetElementId` | string | The DOM ID of the target element on which the comment was added |
    | `context`         | Object | Any context data passed when the comment was added              |
  </Step>
</Steps>

{/* # Additional Configurations

## Allow comments only on certain elements

Provide a list of element DOM IDs where commenting should be allowed.
Comments will be disabled for all other elements.

```jsx
const commentElement = client.getCommentElement();
commentElement.allowedElementIds(['custom-video-player-container']);
``` */}


# Prebuilt Video Player Setup

Use this guide if you want to set up a prebuilt video player from our SDK with collaborative features built in.

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/video-comment.gif)

<Tabs>
  <Tab title="React / Next.js">
    <Steps>
      <Step title="Import VeltVideoPlayer component">
        Import the `VeltVideoPlayer` component.

        ```jsx
        import { VeltVideoPlayer} from '@veltdev/react'
        ```
      </Step>

      <Step title="Add src to VeltVideoPlayer">
        Add your video src URL to the `src` attribute of the `VeltVideoPlayer` component.

        There are a few other properties:

        *   `darkMode` - boolean to enable dark mode
        *   `sync` - boolean to enable sync mode

        ```jsx
        <VeltVideoPlayer 
          src={"https://firebasestorage.googleapis.com/v0/b/snippyly.appspot.com/o/external%2Fvelt.mp4?alt=media&token=d8af2697-c797-4610-b886-ca510b231097"} 
          darkMode={false}
          sync={true}
        />
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    Add your video src URL to the `src` attribute of the `<velt-video-player>` component.

    There are a few other properties:

    *   `dark-mode` - boolean to enable dark mode
    *   `sync` - boolean to enable sync mode

    ```html
    <!-- dark-mode="false" - to disable dark mode -->
    <!-- sync="true" - to enable sync mode -->
    <velt-video-player 
      src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4"
      dark-mode="false"
      sync="true"
    >
    </velt-video-player>

    ```
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import {
    VeltVideoPlayer
  } from '@veltdev/react';

  export default function App() {

    return (
      <div>
        <VeltVideoPlayer 
          src={"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4"} 
          darkMode={false}
          sync={true}
        />
      </div>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Video Player documentation</title>
    </head>
    <body>
      <!-- dark-mode="false" - to disable dark mode -->
      <!-- sync="true" - to enable sync mode -->
      <velt-video-player 
          src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4"
          dark-mode="false"
          sync="true"
      >
      </velt-video-player>
    </body>
  </html>

  ```
</RequestExample>


# Comment Standalone Composer



The Comment Standalone Composer enables you to add comments anywhere in your application. It's designed to work seamlessly with other Velt components and APIs:

*   [Comment Data APIs](/async-collaboration/comments/customize-behavior/retrieve-comments): Fetch and submit comment data.
*   [Comment Thread](/async-collaboration/comments/standalone-components/comment-thread/overview): Render comment threads using fetched data.
*   [Comment Pin](/async-collaboration/comments/standalone-components/comment-pin/overview): Display and position comment pins based on fetched data.

By combining these components, you can create custom comment interfaces such as sidebars, overlays, popovers, or inline comments. This approach offers greater flexibility and control over your comment system's design and functionality.


# Setup



## Add Comment Composer Component

The Comment Composer component allows you to add a comment composer anywhere in your app. You can:

*   Display it on a hotkey press
*   Embed it in your custom sidebar
*   Place it below an article
*   Overlay it on an image
*   and more...

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentComposer />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-composer></velt-comment-composer>
    ```
  </Tab>
</Tabs>


# Comment Pin



The Comment Pin component allows you to manually set the position of Comment Annotations.
This feature is particularly useful for complex UIs where you need precise control over the placement of Comment Pins.

Implementing this feature involves:

**1. Adding comment:** You have two options for adding comments with custom positioning:

*   **a. Velt-Managed Click Events:** Use the `onCommentAdd` method to incorporate custom metadata into the comment object. This metadata will be used later to position the Comment Pin. [Learn more](/async-collaboration/comments/customize-behavior/event-handlers#oncommentadd-event-data-schema)

*   **b. Custom Click Event Handling:** Handle click events on your canvas and use the `addManualComment` method to create a comment with custom metadata. [Learn more](/async-collaboration/comments/customize-behavior/action-methods#3-add-manual-comment)

**2. Retrieving comments data:** Use the `getAllCommentAnnotations` method to fetch all Comment Annotations with their associated custom metadata.
For React developers, we provide hooks for easier integration. [Learn more](/async-collaboration/comments/customize-behavior/retrieve-comments)

**3. Rendering comments Pins:**
Iterate through the retrieved annotations and render the Comment Pin component, using the custom metadata to set each pin's position.


# Setup



<Steps titleSize="h2">
  <Step title="Add custom metadata when comment is added">
    You have two options for adding comments with custom positioning metadata:

    **Option A: Velt-Managed Click Events**

    *   Use the `onCommentAdd` prop of the VeltComments component to add custom metadata when a comment is added.
    *   You need to set the mandatory `commentType: 'manual'` property to the metadata object.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltComments onCommentAdd={(event) => yourMethod(event)} />

        const yourMethod = (event) => {
          event?.addContext({ postion: {x: 200, y: 100}, commentType: 'manual'});
        }
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        const veltCommentsTag = document.querySelector('velt-comments');

        veltCommentsTag?.addEventListener('onCommentAdd', (event) => {
          console.log('*** onCommentAdd ***');
          console.log(event.detail);
          event.detail?.addContext({ postion: {x: 200, y: 100}, commentType: 'manual'});
        });

        ```
      </Tab>
    </Tabs>

    **Option B: Custom Click Event Handling**

    *   Handle click events on your canvas and use the `addManualComment` method to create a comment with custom metadata.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        const context = {
          postion: {x: 200, y: 100},
        };
        const commentElement = useCommentUtils();
        commentElement.addManualComment({ context });
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        const context = {
          postion: {x: 200, y: 100},
        };
        const commentElement = Velt.getCommentElement();
        commentElement.addManualComment({ context: context});
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Retrieve all Comment Annotations">
    Retrieve all `Comment Annotations` using the `useCommentAnnotations()` hook.

    To learn more about the `useCommentAnnotations()` hook, [read here](/api-reference/hooks/hooks#usecommentannotations).

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        let commentAnnotations = useCommentAnnotations()
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        const commentElement = Velt.getCommentElement();
        let subscription = commentElement.getAllCommentAnnotations().subscribe((commentAnnotations) => {
          // console.log(commentAnnotations);
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Render the Velt Comment Pin component and set the position">
    Add the `Velt Comment Pin` component and pass in the `Comment Annotation Id`.
    Now retrieve the `context` to retrieve the custom metadata you set earlier and use it to set the position of the `Comment Pin`.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx

        let commentAnnotations = useCommentAnnotations()

        return (
        <div className='comments-container'>
          {
            commentAnnotations.map((commentAnnotation) => {
              return (
                <div key={commentAnnotation.annotationId} style={{
                  position: 'absolute',
                  left: commentAnnotation.context.position.x + dragPosition.x,
                  top: commentAnnotation.context.position.y + dragPosition.y,
                  transform: 'translate(0%, -100%)'
                }}>
                  <VeltCommentPin annotationId={commentAnnotation.annotationId}></VeltCommentPin>
                </div>
              )
            })
          }
        </div>
        )
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        const commentElement = Velt.getCommentElement();

        let subscription = commentElement.getAllCommentAnnotations().subscribe((commentAnnotations) => {
          renderCommentAnnotations(commentAnnotations);
        });

        const commentsContainer = document.getElementById('comments-container');

        function renderCommentAnnotations(commentAnnotations) {
          commentAnnotations.forEach((commentAnnotation) => {
            if (!document.getElementById(`comment-pin-container-${commentAnnotation.annotationId}`)) {
              // Add Comment Pin if it doesn't exist
              const { x, y } = commentAnnotation.context.position;
              var commentPinContainer = document.createElement('div');
              commentPinContainer.className = 'comment-pin-container';
              commentPinContainer.id = `comment-pin-container-${commentAnnotation.annotationId}`;
              commentPinContainer.style.left = x + 'px';
              commentPinContainer.style.top = y + 'px';
              commentPinContainer.innerHTML = `<velt-comment-pin annotation-id="${commentAnnotation?.annotationId}"></velt-comment-pin>`;
              commentsContainer?.appendChild(commentPinContainer);
            }
          });
        }

        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

<RequestExample>
  ```jsx React / Next.js
  import { VeltCommentPin, useCommentAnnotations } from '@veltdev/react';

  export default function YourDocument() {

    const yourMethod = (event) => {
      event?.addContext({ postion: {x: 200, y: 100}, commentType: 'manual'});
    }

    let commentAnnotations = useCommentAnnotations()

    return (

      <VeltComments onCommentAdd={(event) => yourMethod(event)} />

      <div className='comments-container'>
        {
          commentAnnotations.map((commentAnnotation) => {
            return (
              <div key={commentAnnotation.annotationId} style={{
                position: 'absolute',
                left: commentAnnotation.context.position.x + dragPosition.x,
                top: commentAnnotation.context.position.y + dragPosition.y,
                transform: 'translate(0%, -100%)'
              }}>
                <VeltCommentPin annotationId={commentAnnotation.annotationId}></VeltCommentPin>
              </div>
            )
          })
        }
      </div>
    )
  }
  ```

  ```html HTML
  <script>
  const veltCommentsTag = document.querySelector('velt-comments');

  veltCommentsTag?.addEventListener('onCommentAdd', (event) => {
    console.log('*** onCommentAdd ***');
    console.log(event.detail);
    event.detail?.addContext({ postion: {x: 200, y: 100}, commentType: 'manual'});
  });

  const commentElement = Velt.getCommentElement();

  let subscription = commentElement.getAllCommentAnnotations().subscribe((commentAnnotations) => {
    renderCommentAnnotations(commentAnnotations);
  });

  const commentsContainer = document.getElementById('comments-container');

  function renderCommentAnnotations(commentAnnotations) {
    commentAnnotations.forEach((commentAnnotation) => {
      if (!document.getElementById(`comment-pin-container-${commentAnnotation.annotationId}`)) {
        // Add Comment Pin if it doesn't exist
        const { x, y } = commentAnnotation.context.position;
        var commentPinContainer = document.createElement('div');
        commentPinContainer.className = 'comment-pin-container';
        commentPinContainer.id = `comment-pin-container-${commentAnnotation.annotationId}`;
        commentPinContainer.style.left = x + 'px';
        commentPinContainer.style.top = y + 'px';
        commentPinContainer.innerHTML = `<velt-comment-pin annotation-id="${commentAnnotation?.annotationId}"></velt-comment-pin>`;
        commentsContainer?.appendChild(commentPinContainer);
      }
    });
  }

  </script>
  ```
</RequestExample>


# Customize Behavior



## 1. `onCommentClick` Callback

*   When the user clicks on the comment thread, you can listen to it using this method.
*   Example: Use this to fetch the context and make the necessary app state changes to navigate to the comment.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentThread
        annotationId="COMMENT_ANNOTATION_ID"
        onCommentClick={(data) => handleOnCommentClick(data)}
    />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comment-thread annotation-id="COMMENT_ANNOTATION_ID"></velt-comment-thread>
    <script>
        const commentThreadTag = document.querySelector("velt-comment-thread");
        commentThreadTag.addEventListener('onCommentClick', (event) => {
            console.log('onCommentClick', event.detail);
        });
    </script>
    ```
  </Tab>
</Tabs>

## 2. Pass Comment Annotation Object

*   You can pass a Comment Annotation object directly to render the comment thread
*   When using annotations from other documents:
    *   Comments will be read-only
    *   Reactions and recordings will not be rendered
*   This enables creating Kanban boards by fetching comment annotations from multiple documents using our REST APIs

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentThread annotation={COMMENT_ANNOTATION_OBJECT} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-thread annotation="STRINGIFIED_COMMENT_ANNOTATION_OBJECT"></velt-comment-thread>
    ```
  </Tab>
</Tabs>


# Standalone Comment Thread



*   You can use the Standalone Comment Thread component to build things such as:
    *   a kanban board
    *   your own version of the `Comments Sidebar` component

*   This component does not add any additional functionality. It is just used to render existing comment data.

*   This is a thin wrapper around the [Comment Dialog component](/ui-customization/features/async/comments/comment-dialog/overview).

*   Get the Comment Annotations data using the APIs.

*   Use this component to render the Comment Annotations data.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comment-thread" allow="camera; microphone" className="w-full" height="700px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comment-thread)


# Setup



<Steps titleSize="h2">
  <Step title="Retrieve Comment Annotations">
    *   Retrieve all comment annotations data.
    *   [Learn more](/async-collaboration/comments/customize-behavior/retrieve-comments).

    <Tabs>
      <Tab title="React / Next.js">
        Using Hooks:

        ```jsx
        let commentAnnotations = useCommentAnnotations()
        ```

        Using API:

        ```js
        const commentElement = client.getCommentElement();
        let subscription = commentElement.getAllCommentAnnotations().subscribe((commentAnnotations) => {
          // console.log(commentAnnotations);
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        const commentElement = Velt.getCommentElement();
        let subscription = commentElement.getAllCommentAnnotations().subscribe((commentAnnotations) => {
          // console.log(commentAnnotations);
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add the Velt Comment Thread component">
    *   Iterate over the `Comment Annotations` array and add the `Velt Comment Thread` component.
    *   Pass the `annotation Id` prop to set the specific Comment Thread data.

    Here's an improved example:

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx

        let commentAnnotations = useCommentAnnotations()

        return (
          <div>
            {commentAnnotations.map((x,i) => <VeltCommentThread key={i} annotationId={x.annotationId}/>)}
          </div>
        )
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <!-- 
          If you are using pure html, inject <velt-comment-thread annotation-id="ANNOTATION_ID"></velt-comment-thread>
          In other frameworks, you can loop over the comments inside the template itself
        -->
        <velt-comment-thread annotation-id="ANNOTATION_ID"></velt-comment-thread>
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

<RequestExample>
  ```jsx React / Next.js
  import { VeltCommentThread, useCommentAnnotations } from '@veltdev/react';

  export default function YourDocument() {

    let commentAnnotations = useCommentAnnotations()

    return (
      <div>
        {commentAnnotations.map((x,i) => <VeltCommentThread key={i} annotationId={x.annotationId}/>)}
      </div>
    )
  }
  ```

  ```js Other Frameworks
  const commentElement = client.getCommentElement();
  let subscription = commentElement.getAllCommentAnnotations().subscribe((comments) => {
      // If you are using pure html, inject <velt-comment-thread annotation-id="ANNOTATION_ID"></velt-comment-thread>
      // In other frameworks, you can loop over the comments inside the template itself
  });

  //To unsubscribe from the subscription:
  subscription?.unsubscribe()
  ```
</RequestExample>


# Customize Behavior



## 1. Get Notifications Data

*   Get the notifications data for the current user.
*   Returns [`Notification[]`](/api-reference/models/Notification)

<Tabs>
  <Tab title="React / Next.js with Hooks">
    ```jsx
    const notificationData = useNotificationsData();
    ```
  </Tab>

  <Tab title="React / Next.js">
    ```jsx
    const notificationElement = client.getNotificationElement();

    let subscription = notificationElement.getNotificationsData().subscribe((notifications) => {
        console.log("Notifications: ", notifications)
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const notificationElement = Velt.getNotificationElement();

    let subscription = notificationElement.getNotificationsData().subscribe((notifications) => {
        console.log("Notifications: ", notifications)
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

## 2. Take action when a Notification is clicked

*   The `onNotificationClick` event fires when a notification is clicked in the Notifications Panel.
*   It returns a [`Notification`](/api-reference/models/Notification) object with details about the clicked notification.
*   Listen to this event via either the Notification Tool or the Notification Panel, but not both.
*   Use this event to implement custom actions in response to notification clicks, such as navigating to a specific part of the app.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltNotificationsTool onNotificationClick={(notification) => onNotificationClickEvent(notification)} />

    <VeltNotificationsPanel onNotificationClick={(notification) => onNotificationClickEvent(notification)} />

    const onNotificationClickEvent = (notification) => {
    	console.log('onNotificationClick: ', notification);
    }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
      const notificationsTool = document.querySelector('velt-notifications-tool');
    	notificationsTool?.addEventListener('onNotificationClick', (event) => {
    	  console.log('onNotificationClick from Tool: ', event.detail);
      });

      const notificationsPanel = document.querySelector('velt-notifications-panel');
    	notificationsPanel?.addEventListener('onNotificationClick', (event) => {
    	  console.log('onNotificationClick from Panel: ', event.detail);
      });
    ```
  </Tab>
</Tabs>

## 3. Configure Custom Tabs

*   Using this config, you can customize the name of the tabs or disable them altogether.
*   By default, all the three tabs are enabled.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    You can set it on Notifications Tool:

    ```jsx
    <VeltNotificationsTool tabConfig={{
        "forYou": {
            name: 'Custom For You',
            enable: true,
        },
        "documents": {
            name: 'Custom Document',
            enable: false,
        },
        "all": {
            name: 'Custom All',
            enable: true,
        },
    }
    } />
    ```

    You can alternatively set it on Notifications Panel if you have directly embedded it:

    ```jsx
    <VeltNotificationsPanel tabConfig={{
        "forYou": {
            name: 'Custom For You',
            enable: true,
        },
        "documents": {
            name: 'Custom Document',
            enable: false,
        },
        "all": {
            name: 'Custom All',
            enable: true,
        },
    }
    } />
    ```

    **Using APIs:**

    ```jsx
    const notificationElement = useNotificationUtils();

    ​​const tabConfig = {
    	"forYou": {
    		name: 'Custom For You',
    		enable: true,
    	},
    	"documents": {
    		name: 'Custom Document',
    		enable: false,
    	},
    	"all": {
    		name: 'Custom All',
    		enable: true,
    	},
    };

    notificationElement.setTabConfig(tabConfig);
    ```
  </Tab>

  <Tab title="React / Next.js">
    You can set it on Notifications Tool:

    ```jsx
    <VeltNotificationsTool tabConfig={{
        "forYou": {
            name: 'Custom For You',
            enable: true,
        },
        "documents": {
            name: 'Custom Document',
            enable: false,
        },
        "all": {
            name: 'Custom All',
            enable: true,
        },
    }
    } />
    ```

    You can alternatively set it on Notifications Panel if you have directly embedded it:

    ```jsx
    <VeltNotificationsPanel tabConfig={{
        "forYou": {
            name: 'Custom For You',
            enable: true,
        },
        "documents": {
            name: 'Custom Document',
            enable: false,
        },
        "all": {
            name: 'Custom All',
            enable: true,
        },
    }
    } />
    ```

    **Using APIs:**

    ```jsx
    const notificationElement = client.getNotificationElement();

    ​​const tabConfig = {
    	"forYou": {
    		name: 'Custom For You',
    		enable: true,
    	},
    	"documents": {
    		name: 'Custom Document',
    		enable: false,
    	},
    	"all": {
    		name: 'Custom All',
    		enable: true,
    	},
    };

    notificationElement.setTabConfig(tabConfig);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const tabConfig = {
    	"forYou": {
    		name: 'Custom For You',
    		enable: true,
    	},
    	"documents": {
    		name: 'Custom Document',
    		enable: false,
    	},
    	"all": {
    		name: 'Custom All',
    		enable: true,
    	},
    };

    // Set it using Notifications Tool
    const notificationsTool = document.querySelector('velt-notifications-tool');
    notificationsTool?.setAttribute("tab-config", JSON.stringify(tabConfig));

    // Or, set it using Notifications Panel
    const notificationsPanel = document.querySelector('velt-notifications-panel');
    notificationsPanel?.setAttribute("tab-config", JSON.stringify(tabConfig));
    ```

    **Using APIs:**

    ```jsx
    const notificationElement = Velt.getNotificationElement();

    ​​const tabConfig = {
    	"forYou": {
    		name: 'Custom For You',
    		enable: true,
    	},
    	"documents": {
    		name: 'Custom Document',
    		enable: false,
    	},
    	"all": {
    		name: 'Custom All',
    		enable: true,
    	},
    };

    notificationElement.setTabConfig(tabConfig);
    ```
  </Tab>
</Tabs>

## 4. Set maximum days for which Notifications should be displayed

Notifications older than the specified number of days will not be displayed.

Default: 15 days.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    ```jsx
    <VeltNotificationsTool maxDays={15} />
    ```

    **Using API:**

    ```jsx
    const notificationElement = useNotificationUtils();
    notificationElement.setMaxDays(15);
    ```
  </Tab>

  <Tab title="React / Next.js">
    ```jsx
    <VeltNotificationsTool maxDays={15} />
    ```

    **Using API:**

    ```jsx
    const notificationElement = client.getNotificationElement();
    notificationElement.setMaxDays(15);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-notifications-tool max-days="15"></velt-notifications-tool>
    ```

    **Using APIs:**

    ```jsx
    const notificationElement = Velt.getNotificationElement();
    notificationElement.setMaxDays(15);
    ```
  </Tab>
</Tabs>

## 5. Change how the Notifications Panel is opened

Notificaitons Panel opens in one of the following ways:

*   `popover`: It opens as a popover on the Notification Tool.
*   `sidebar`: It opens as a sidebar from the right edge of the screen.

Default: `popover`.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    ```jsx
    <VeltNotificationsTool panelOpenMode={'sidebar'} />
    ```
  </Tab>

  <Tab title="React / Next.js">
    ```jsx
    <VeltNotificationsTool panelOpenMode={'sidebar'} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-notifications-tool panel-open-mode="sidebar"></velt-notifications-tool>
    ```
  </Tab>
</Tabs>

## 6. Configure visibility of read notifications in the "For You" tab

*   You can control whether read notifications are displayed in the "For You" tab. By default, read notifications are removed from this tab.
*   This feature allows you to customize the visibility of read notifications in the "For You" tab, providing more flexibility in how notifications are displayed to users.

Default: `false`.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    Using Props:

    ```jsx
    <VeltNotificationsTool readNotificationsOnForYouTab={true} />
    <VeltNotificationsPanel readNotificationsOnForYouTab={true} />
    ```

    Using APIs:

    ```jsx
    const notificationElement = useNotificationUtils();
    // Enable to keep read notifications in the for you tab
    notificationElement.enableReadNotificationsOnForYouTab();
    // Disable to hide read notifications in the for you tab
    notificationElement.disableReadNotificationsOnForYouTab();
    ```
  </Tab>

  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltNotificationsTool readNotificationsOnForYouTab={true} />
    <VeltNotificationsPanel readNotificationsOnForYouTab={true} />
    ```

    Using APIs:

    ```jsx
    const notificationElement = client.getNotificationElement();
    // Enable to keep read notifications in the for you tab
    notificationElement.enableReadNotificationsOnForYouTab();
    // Disable to hide read notifications in the for you tab
    notificationElement.disableReadNotificationsOnForYouTab();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-notifications-tool read-notifications-on-for-you-tab="true">
    </velt-notifications-tool>
    <velt-notifications-panel read-notifications-on-for-you-tab="true">
    </velt-notifications-panel>
    ```

    Using API:

    ```html
    <script>
      // Using APIs
      const notificationElement = Velt.getNotificationElement();
      // Enable to keep read notifications in the for you tab
      notificationElement.enableReadNotificationsOnForYouTab();
      // Disable to hide read notifications in the for you tab
      notificationElement.disableReadNotificationsOnForYouTab();
    </script>
    ```
  </Tab>
</Tabs>

## 7. Mark All Notifications as Read

*   Mark all notifications as read, either globally or for a specific tab.
*   Using 'all' or 'document' as the `tabId` marks all notifications as read across all tabs (equivalent to calling `setAllNotificationsAsRead()` without arguments).
*   Using 'for-you' as the `tabId` only marks notifications in the 'for-you' tab as read.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    const notificationElement = client.getNotificationElement();

    // Mark all notifications as read
    notificationElement.setAllNotificationsAsRead();

    // Mark all notifications as read for a specific tab
    notificationElement.setAllNotificationsAsRead({ tabId: 'for-you' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'all' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'document' });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const notificationElement = Velt.getNotificationElement();

    // Mark all notifications as read
    notificationElement.setAllNotificationsAsRead();

    // Mark all notifications as read for a specific tab
    notificationElement.setAllNotificationsAsRead({ tabId: 'for-you' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'all' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'document' });
    ```
  </Tab>
</Tabs>

## 8. Get Unread Notifications Count

*   Retrieve the count of unread notifications, which includes a breakdown for different tabs.
*   The 'Document' tab is not included in the response because it contains all the notifications present in the 'All' tab.

**Sample response:**

```javascript
{ 
  forYou: 4, // # of unread notifications in the "For You" tab
  all: 5     // # of unread notifications in the "All" or "Document" tab
}
```

<Tabs>
  <Tab title="React / Next.js">
    Using Hooks:

    ```jsx
    const unreadCount = useUnreadNotificationsCount();

    useEffect(() => {
      console.log('Unread Count', unreadCount);
    }, [unreadCount]);
    ```

    Using API:

    ```javascript
    const notificationElement = client.getNotificationElement();
    notificationElement.getUnreadNotificationsCount().subscribe((data) => {
      console.log('Unread notifications count:', data);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const notificationElement = Velt.getNotificationElement();
    notificationElement.getUnreadNotificationsCount().subscribe((data) => {
      console.log('Unread notifications count:', data);
    });
    ```
  </Tab>
</Tabs>

## 9. Mark a Single Notification as Read

*   Mark a single notification as read using its notificationId.
*   The notification will be marked as read in all tabs.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    const notificationElement = client.getNotificationElement();
    notificationElement.markNotificationAsReadById("notificationId");
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const notificationElement = Velt.getNotificationElement();
    notificationElement.markNotificationAsReadById("notificationId");
    ```
  </Tab>
</Tabs>


# In-app Notifications



There are two components associated with In-app Notifications feature:

*   `Velt Notifications Tool`: This opens the Notifications Panel.
*   `Velt Notifications Panel`: This shows all the `Notifications` grouped in categories.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=notifications" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=notifications)


# Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/Notification_Dialog_Box.png)

<Steps titleSize="h2">
  <Step title="Enable Notifications in the Velt Console">
    *   Go to the [Notifications section](https://console.velt.dev/dashboard/config/notification) in the Configurations section of the Velt Console and enable Notifications.

    <Warning> Notifications will not work if you do not enable this first.</Warning>
  </Step>

  <Step title="Add the Notifications Tool component">
    *   Place the `Velt Notifications Tool` component wherever you want the Notifications button to appear.

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/Notification_Dialog_Box.png)

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <div className="toolbar">
          <VeltNotificationsTool/>
        </div>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <div className="toolbar">
          <velt-notifications-tool></velt-notifications-tool>
        </div>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="(optional) Embed Notifications Panel">
    *   By default, the Velt Notifications Panel is automatically added or removed when you use the `Velt Notifications Tool`.
    *   However, if you want to create a dedicated page or dedicated section for Notifications, you can embed the Velt Notifications Panel component directly there.

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/Notification_Dialog_Box.png)

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <div className="toolbar">
          <VeltNotificationsPanel />
        </div>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        <div className="toolbar">
          <velt-notifications-panel></velt-notifications-panel>
        </div>
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

<RequestExample>
  ```jsx React / Next.js
  import { VeltNotificationsTool } from '@veltdev/react';

  function YourComponent() {

    return (
      <div className="toolbar">
        <VeltNotificationsTool />
      </div>
    )
    
  }
  ```

  ```html HTML
  <div className="toolbar">
    <velt-notifications-tool></velt-notifications-tool>
  </div>
  ```
</RequestExample>


# Inline Reactions



This allows users to add emoji reactions to specific parts of your UI (eg: posts, images etc). This is great for quick emotional responses or feedback.

Add `Velt Inline Reactions Section` component to your app to enable Inline Reactions.

<Frame>
  <iframe src="https://docs-mini-demo.vercel.app/reactions-inline" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="300px" />
</Frame>

[Open in larger window](https://docs-mini-demo.vercel.app/reactions-inline)


# Setup



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Velt Inline Reactions Section component">
        Import the `VeltInlineReactionsSection` component.

        ```js
        import { VeltInlineReactionsSection } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add container to hold Inline Reactions component">
        *   Create an element to hold your Inline Reactions component, such as a `div` or `section`.
        *   Add a unique element `id` to it.

        ```jsx
        <section id="container-id">
        	<div>Your Article</div>
        </section>
        ```
      </Step>

      <Step title="Add VeltInlineReactionsSection component">
        *   Add `VeltInlineReactionsSection` component inside your container.
        *   Add `targetReactionElementId` property to the Velt Inline Reactions component. This needs to match the id you set to the container. This binds the Inline Reactions component with the desired container.

        ```jsx
        <section id="container-id">
        	<div>Your Article</div>

        	<VeltInlineReactionsSection
        		targetReactionElementId="container-id"
        	/>

        </section>
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add container to hold Inline Reactions component">
        *   Create an element to hold your Inline Reactions component, such as a `div` or `section`.
        *   Add a unique element `id` to it.

        ```html
        <section id="container-id">
        	<div>Your Article</div>
        </section>
        ```
      </Step>

      <Step title="Add Velt Inline Reactions Section component">
        *   Add `velt-inline-reactions-section` component inside your container.
        *   Add `target-reaction-element-id` property to the Velt Inline Reactions component. This needs to match the id you set to the container. This binds the Inline Reactions component with the desired container.

        ```jsx

        <section id="container-id">
        	<div>Your Article</div>

        	<velt-inline-reactions-section
        		target-reaction-element-id="container-id">
        	</velt-inline-reactions-section>

        </section>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { VeltInlineReactionsSection } from '@veltdev/react';

  export default function App() {

    return (
        <section id="container-id">
          <div>Your Article</div>

          <VeltInlineReactionsSection
            targetReactionElementId="container-id"
          />

        </section>  
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <body>

      <section id="container-id">
        <div>Your Article</div>

        <velt-inline-reactions-section
          target-reaction-element-id="container-id">
        </velt-inline-reactions-section>

      </section>

    </body>
  </html>
  ```
</RequestExample>


# Customize Behavior



## 1. buttonLabel

Sets a custom label for the `Velt Recorder Tool`.

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltRecorderTool buttonLabel="Your Label Text" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-recorder-tool buttonLabel="Your Label Text"></velt-recorder-tool>
    ```
  </Tab>
</Tabs>

## 2. enableRecordingCountdown

Controls whether to display a countdown timer before a recording starts.

Default: `enabled`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    const recorderElement = client.getRecorderElement();
    recorderElement.enableRecordingCountdown();
    recorderElement.disableRecordingCountdown();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const recorderElement = Velt.getRecorderElement();
    recorderElement.enableRecordingCountdown();
    recorderElement.disableRecordingCountdown();
    ```
  </Tab>
</Tabs>

## 3. enableRecordingTranscription

Controls whether to enable AI transcription for recordings.

Default: `enabled`

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    const recorderElement = client.getRecorderElement();
    recorderElement.enableRecordingTranscription();
    recorderElement.disableRecordingTranscription();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const recorderElement = Velt.getRecorderElement();
    recorderElement.enableRecordingTranscription();
    recorderElement.disableRecordingTranscription();
    ```
  </Tab>
</Tabs>

## 4. getRecordingDataByRecorderId

Fetches recording data (transcript, summary, and URLs) for a recording ID and returns a [RecorderData](/api-reference/models/RecorderData) object.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hook:**

    ```jsx
    const recorderData = useRecordingDataByRecorderId('-O9yTMWmEe5u6YGX8EFV');

    useEffect(() => {
        console.log('Recorder Data: ', recorderData);
    }, [recorderData]);
    ```

    **Using API:**

    ```jsx
    const recorderElement = client.getRecorderElement();

    recorderElement.getRecordingDataByRecorderId("-O9yGiYS8lehOXMpQf4j").subscribe((recorderData) => {
        console.log('Recorder Data: ', recorderData);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const recorderElement = Velt.getRecorderElement();

    recorderElement.getRecordingDataByRecorderId("-O9yGiYS8lehOXMpQf4j").subscribe((recorderData) => {
        console.log('Recorder Data: ', recorderData);
    });
    ```
  </Tab>
</Tabs>

## 5. mode

The `Velt Recorder Control Panel` has two display modes:

*   `floating`: Shows a preview in the bottom left corner of the page, regardless of component placement
*   `thread`: Displays the component at its placed location in the DOM

`Default: "floating"`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltRecorderControlPanel mode="floating" />
    <VeltRecorderControlPanel mode="thread" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-recorder-control-panel mode="floating"></velt-recorder-control-panel>
    <velt-recorder-control-panel mode="thread"></velt-recorder-control-panel>
    ```
  </Tab>
</Tabs>

## 6. onDelete

When a recording is deleted by its creator, the `Velt Recorder Player` component emits an `onDelete` event containing the recorder ID. You can listen for this event to perform any necessary cleanup.

The event returns an object with the following field:

| Field | Type   | Description                    |
| ----- | ------ | ------------------------------ |
| id    | string | The ID of the deleted recorder |

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltRecorderPlayer recorderId={RECORDER_ID} onDelete={(data) => yourDeleteMethod(data)} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const recorderPlayer = document.querySelector('velt-recorder-player');
    recorderPlayer?.addEventListener('onDelete', (s) => {
        console.log('onDelete', s.detail);
    });
    ```
  </Tab>
</Tabs>

## 7. onRecordedData

The `onRecordedData` callback is triggered when a recording is completed. It provides the following data:

| Field | Type   | Description                                                                                                     |
| ----- | ------ | --------------------------------------------------------------------------------------------------------------- |
| id    | string | Unique identifier for the recording                                                                             |
| tag   | string | HTML tag to embed the recording player (e.g. `<velt-recorder-player recorder-id="123"></velt-recorder-player>`) |

<Tabs>
  <Tab title="React / Next.js">
    **Using Hooks:**

    ```jsx
      const recorderAddEvent = useRecorderAddHandler();

      useEffect(() => {
        console.log('recorderAddEvent', recorderAddEvent);
      }, [recorderAddEvent]);
    ```

    **Using API:**

    ```jsx
      const recorderElement = client.getRecorderElement();
      recorderElement.onRecordedData().subscribe((recorderAddEvent) => {
        console.log(recorderAddEvent);
      });
    ```

    **Using Event Listener:**

    ```jsx
      const onRecordedData = (recorderAddEvent) => {
        console.log(recorderAddEvent);
      }
      return (
        <VeltRecorderControlPanel mode="thread" onRecordedData={onRecordedData} />
      )

    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using API:**

    ```jsx
      const recorderElement = Velt.getRecorderElement();
      recorderElement.onRecordedData().subscribe((recorderAddEvent) => {
        console.log(recorderAddEvent);
      });
    ```

    **Using Event Listener:**

    ```js
    const recorderControlPanel = document.querySelector('velt-recorder-control-panel');
    recorderControlPanel?.addEventListener('onRecordedData', (s) => {
        console.log('onRecordedData', s.detail);
    });
    ```
  </Tab>
</Tabs>

## 8. summary

Controls whether to display a summary transcript of the recording. When enabled, an AI-generated summary of the recording's content will be shown.

Default: `true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltRecorderPlayer summary={true}/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-recorder-player summary={true}></velt-recorder-player>
    ```
  </Tab>
</Tabs>

## 9. type

Sets the recording mode for the `Velt Recorder Tool`.

Available modes:

*   `all` - Records audio, video and screen
*   `audio` - Records audio only
*   `video` - Records video only
*   `screen` - Records screen only

Default: `audio`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltRecorderTool type='all' />
    <VeltRecorderTool type='audio' />
    <VeltRecorderTool type='video' />
    <VeltRecorderTool type='screen' />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-recorder-tool type='all'></velt-recorder-tool>
    <velt-recorder-tool type='audio'></velt-recorder-tool>
    <velt-recorder-tool type='video'></velt-recorder-tool>
    <velt-recorder-tool type='screen'></velt-recorder-tool>
    ```
  </Tab>
</Tabs>


# Recorder

The Recorder allows your users to create audio, screen, and video recordings.

The Velt Recorder consists of 4 key components:

*   **Velt Recorder Notes**: Enables pinning recordings to specific locations on the screen
*   **Velt Recorder Tool**: A button to initiate recordings
*   **Velt Recorder Control Panel**: Controls for managing active recordings (start/stop/pause)
*   **Velt Recorder Player**: Plays back recordings using their unique ID

<Tabs>
  <Tab title="All">
    <Frame>
      <iframe src="https://recorder-landing-page-demo.vercel.app/?type=all&backgroundColor=black&darkMode=true" allow="camera; microphone" className="w-full" height="500px" />
    </Frame>

    [Open in larger window](https://recorder-landing-page-demo.vercel.app/?type=all\&backgroundColor=black\&darkMode=true)
  </Tab>

  <Tab title="Audio">
    <Frame>
      <iframe src="https://recorder-landing-page-demo.vercel.app/?type=audio&backgroundColor=black&darkMode=true" allow="camera; microphone" className="w-full" height="500px" />
    </Frame>

    [Open in larger window](https://recorder-landing-page-demo.vercel.app/?type=audio\&backgroundColor=black\&darkMode=true)
  </Tab>

  <Tab title="Video">
    <Frame>
      <iframe src="https://recorder-landing-page-demo.vercel.app/?type=video&backgroundColor=black&darkMode=true" allow="camera; microphone" className="w-full" height="500px" />
    </Frame>

    [Open in larger window](https://recorder-landing-page-demo.vercel.app/?type=video\&backgroundColor=black\&darkMode=true)
  </Tab>

  <Tab title="Screen">
    <Frame>
      <iframe src="https://recorder-landing-page-demo.vercel.app/?type=screen&backgroundColor=black&darkMode=true" allow="camera; microphone" className="w-full" height="500px" />
    </Frame>

    [Open in larger window](https://recorder-landing-page-demo.vercel.app/?type=screen\&backgroundColor=black\&darkMode=true)
  </Tab>
</Tabs>


# null



<Steps>
  <Step title="Import Velt Recorder components">
    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        import { 
          VeltRecorderNotes, 
          VeltRecorderTool, 
          VeltRecorderControlPanel, 
          VeltRecorderPlayer 
        } from '@veltdev/react'
        ```
      </Tab>

      <Tab title="HTML/ Other frameworks">
        Not needed.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add the Velt Recorder Notes component">
    Add the `Velt Recorder Notes` component to the root of your app.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltProvider>
          <VeltRecorderNotes/>
        </VeltProvider>
        ```
      </Tab>

      <Tab title="HTML/ Other frameworks">
        ```html
        <velt-recorder-notes></velt-recorder-notes>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add the Velt Recorder Tool component">
    *   Add the `Velt Recorder Tool` component wherever you want the recorder button to appear.
    *   Set the `type` attribute of the `Velt Recorder Tool` component to one of the following:
        *   `all`
        *   `audio`
        *   `video`
        *   `screen`

    <Tabs>
      <Tab title="React / Next.js">
        ```js
        <div className="toolbar">
          <VeltRecorderTool type='all' />
        </div>
        ```
      </Tab>

      <Tab title="HTML/ Other frameworks">
        ```html
        <div className="toolbar">
          <velt-recorder-tool type='all'></velt-recorder-tool>
        </div>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add the Velt Recorder Control Panel component">
    *   Add the `Velt Recorder Control Panel` component wherever you want the control panel to appear.
    *   When a user clicks on the `Velt Recorder Tool` button, the `Velt Recorder Control Panel` component will show the recording preview with options to save, pause, or delete the recording.
    *   Set the `mode` attribute on the `VeltRecorderControlPanel` component to either `floating` (default) or `thread`.

    To  learn more about `floating` or `thread` mode [read here](/async-collaboration/recorder/customize-behavior#5-mode).

    <Tabs>
      <Tab title="React / Next.js">
        ```js
        <div className="toolbar">
          <VeltRecorderTool type='all' />
          <VeltRecorderControlPanel mode="thread" />
        </div>
        ```
      </Tab>

      <Tab title="HTML/ Other frameworks">
        ```html
        <div className="toolbar">
          <velt-recorder-tool type='all'></velt-recorder-tool>
          <velt-recorder-control-panel mode="thread"></velt-recorder-control-panel>
        </div>
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add the Velt Recorder Player component">
    *   Add the `Velt Recorder Player` component wherever you want to show recordings.
    *   The `Velt Recorder Player` component displays the recorded data with controls such as pause, play and delete.
    *   Set the `recorderId` of the `Velt Recorder Player` component as the Id of the recording you are trying to show.

    <Tabs>
      <Tab title="React / Next.js">
        ```js
        <div className="video-player">
          <VeltRecorderPlayer recorderId={RECORDER_ID} />
        </div>
        ```
      </Tab>

      <Tab title="HTML/ Other frameworks">
        ```html
        <div className="video-player">
          <velt-recorder-player recorderId="RECORDER_ID"></velt-recorder-player>
        </div>
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

<RequestExample>
  ```js React / Next.js
  import { VeltRecorderTool, VeltRecorderControlPanel, VeltRecorderPlayer } from '@veltdev/react'

  function TaskInputBox() {
      return (
        <div className="toolbar"> {/* some component that holds your recording components */}
          <VeltRecorderTool type='all' /> {/* Put this where you want the Recorder button to appear */}
          <VeltRecorderControlPanel mode="floating" /> {/* Put this where you want the Recorder control panel to appear */}
        </div>
        <div className="video-player"> {/* some component that holds your video player */}
          <VeltRecorderPlayer recorderId={RECORDER_ID} /> {/* Put this where you want to show the recorded data */}
        </div>
      )
  }
  ```

  ```html HTML
  <div>
        <div class="toolbar"> <!--  some component that holds your recording components -->
          <velt-recorder-tool type='all'></velt-recorder-tool> <!-- Put this where you want the Recorder button to appear -->
          <velt-recorder-control-panel mode="floating"></velt-recorder-control-panel> <!-- Put this where you want the Recorder control panel to appear -->
        </div>
        <div class="video-player"> <!-- some component that holds your video player -->
          <velt-recorder-player recorderId="RECORDER_ID"></velt-recorder-player> <!-- Put this where you want to show the recorded data -->
        </div>
  </div>
  ```
</RequestExample>


# Customize Behavior



## Customize for `Location` specific tracking

<Tabs>
  <Tab title="React / Next.js with Hooks">
    The hook will automatically unsubscribe from the subscription when the component dismounts.

    ```jsx
    import { useUniqueViewsByDate, useUniqueViewsByUser } from '@veltdev/react';
    // to get document level views by date
    const viewsByDate = useUniqueViewsByDate();
    // to get location level views by date
    const viewsByDateForLocation = useUniqueViewsByDate('your-location-id');

    // to get document level views by user
    const viewsByUser = useUniqueViewsByUser();
    // to get location level views by user
    const viewsByUserForLocation = useUniqueViewsByUser('your-location-id');
    ```
  </Tab>

  <Tab title="React / Next.js">
    If you want to specify `Location` specific tracking, you can add two additional properties:

    *   type - this should be either 'document' or 'location' (default: 'location')
    *   location-id - if type is 'location', you can provide a location id here

    ```jsx
    <div className="toolbar">
      <VeltViewAnalytics type="location" location-id="MY_LOCATION_ID" />
    </div>
    ```

    API Methods:

    ```jsx
    const viewsElement = client.getViewsElement();

    // to get unique views by user
    let subscription = viewsElement.getUniqueViewsByUser().subscribe((viewsByUser) => {
    	console.log('Unique views by user: ', viewsByUser);
    });
    // you can optionally pass client-location-id to get unique views by users for that location
    let subscription = viewsElement.getUniqueViewsByUser('your-location-id').subscribe((viewsByUser) => {
    	console.log('Unique views by date for location: ', viewsByUser);
    });

    // to get unique views by date
    let subscription = viewsElement.getUniqueViewsByDate().subscribe((viewsByDate) => {
    	console.log('Unique views by date: ', viewsByDate);
    });
    // you can optionally pass client-location-id to get unique views by date for that location
    let subscription = viewsElement.getUniqueViewsByDate('your-location-id').subscribe((viewsByDate) => {
    	console.log('Unique views by date for location: ', viewsByDate);
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Other Frameworks">
    If you want to specify `Location` specific tracking, you can add two additional properties:

    *   type - this should be either 'document' or 'location' (default: 'location')
    *   location-id - if type is 'location', you can provide a location id here

    ```js
    <div className="toolbar">
      <velt-view-analytics
    	type="location"
    	location-id="your-location-id"
      ></velt-view-analytics>
    </div>
    ```

    API Methods:

    ```jsx
    const viewsElement = client.getViewsElement();

    // to get unique views by user
    let subscription = viewsElement.getUniqueViewsByUser().subscribe((viewsByUser) => {
    	console.log('Unique views by user: ', viewsByUser);
    });
    // you can optionally pass client-location-id to get unique views by users for that location
    let subscription = viewsElement.getUniqueViewsByUser('your-location-id').subscribe((viewsByUser) => {
    	console.log('Unique views by date for location: ', viewsByUser);
    });

    // to get unique views by date
    let subscription = viewsElement.getUniqueViewsByDate().subscribe((viewsByDate) => {
    	console.log('Unique views by date: ', viewsByDate);
    });

    // you can optionally pass client-location-id to get unique views by date for that location
    let subscription = viewsElement.getUniqueViewsByDate('your-location-id').subscribe((viewsByDate) => {
    	console.log('Unique views by date for location: ', viewsByDate);
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>


# View Analytics



<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=view-analytics" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=view-analytics)


# Setup



![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/Trends.png)

<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import the VeltViewAnalytics component from @veltdev/react">
        Import the `VeltViewAnalytics` component

        ```jsx
        import { VeltViewAnalytics } from '@veltdev/react';
        ```
      </Step>

      <Step title="Place the VeltViewAnalytics component">
        Place the `VeltViewAnalytics` component wherever you want the View Analytics component to appear.

        ```jsx
        <div className="toolbar">
          <VeltViewAnalytics />
        </div>
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Place the velt-view-analytics component">
        Place the `<velt-view-analytics>` component wherever you want the View Analytics component to appear.

        ```jsx
        <div className="toolbar">
          <velt-view-analytics></velt-view-analytics>
        </div>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { VeltViewAnalytics } from '@veltdev/react';

  function YourComponent() {

    return (
      <div className="toolbar">
        <VeltViewAnalytics />
      </div>
    )
    
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");
        }
      </script>
    </head>
    <body>
      <div className="toolbar">
        <velt-view-analytics></velt-view-analytics>
      </div>
      
    </body>
  </html>
  ```
</RequestExample>


# null



## Getting Started

<CardGroup cols={2}>
  <Card title="Quickstart" href="/get-started/quickstart" icon="circle-play" color="#7CE38B" iconType="light">
    Set up Velt with a fresh App
  </Card>

  <Card title="Setup" href="/get-started/setup" icon="gear" color="#77BDFB" iconType="light">
    Integrate Velt with an existing app
  </Card>
</CardGroup>

## Popular Features

<CardGroup cols={2}>
  <Card title="Comments" href="/async-collaboration/comments/overview" icon="comment" color="#FAA356" iconType="light">
    Enable contextual discussions within your app
  </Card>

  <Card title="In-app Notifications" href="/async-collaboration/notifications/overview" icon="bell" color="#FAA356" iconType="light">
    Notify users about comment updates or add custom app notifications
  </Card>

  <Card title="Recorder" href="/async-collaboration/recorder/overview" icon="video" color="#FAA356" iconType="light">
    Loom-style audio, video & screen recording with AI transcription
  </Card>

  <Card title="Huddle" href="/realtime-collaboration/huddle/overview" icon="headphones" color="#FAA356" iconType="light">
    Slack-style huddle calls within your app
  </Card>
</CardGroup>

## Async Collaboration

<CardGroup cols={3}>
  <Card title="Comments" href="/async-collaboration/comments/overview" icon="comment" color="#77BDFB" iconType="light">
    Leave a comment anywhere
  </Card>

  <Card title="Comments Sidebar" href="/async-collaboration/comments-sidebar/overview" icon="sidebar" color="#77BDFB" iconType="light">
    A sidebar that holds your comments
  </Card>

  <Card title="In-app Notifications" href="/async-collaboration/notifications/overview" icon="bell" color="#FAA356" iconType="light">
    Notification center in your app
  </Card>

  <Card title="Recorder" href="/async-collaboration/recorder/overview" icon="video" color="#FAA356" iconType="light">
    Embeddable audio, video & screen recording
  </Card>

  <Card title="Media Player Comments" href="/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup" icon="circle-play" color="#77BDFB" iconType="light">
    Frame.io style comments on video
  </Card>

  <Card title="System Comments" href="/api-reference/rest-apis/comments-feature/comment-annotations/add-comment-annotations" icon="server" color="#77BDFB" iconType="light">
    Leave comments using an API
  </Card>

  <Card title="Reactions" href="/async-collaboration/reactions/overview" icon="heart" color="#FAA356" iconType="light">
    Add reactions to components
  </Card>

  <Card title="View Analytics" href="/async-collaboration/view-analytics/overview" icon="chart-line" color="#FAA356" iconType="light">
    Show which users viewed a document
  </Card>

  <Card title="Arrows" href="/async-collaboration/arrows/overview" icon="arrow-up-right" color="#77BDFB" iconType="light">
    Point at what is important
  </Card>
</CardGroup>

## Realtime Collaboration

<CardGroup cols={3}>
  <Card title="Live State Sync" href="/realtime-collaboration/live-state-sync/overview" icon="rotate" color="#7CE38B" iconType="light">
    Sync the state of your app realtime
  </Card>

  <Card title="Single Editor Mode" href="/realtime-collaboration/single-editor-mode/overview" icon="lock" color="#7CE38B" iconType="light">
    Lock access to a single editor
  </Card>

  <Card title="Presence" href="/realtime-collaboration/presence/overview" icon="circle-user" color="#7CE38B" iconType="light">
    See who else is browsing online
  </Card>

  <Card title="Cursors" href="/realtime-collaboration/cursors/overview" icon="arrow-pointer" color="#7CE38B" iconType="light">
    See where everyone else is browsing
  </Card>

  <Card title="Follow Me Mode" href="/realtime-collaboration/flock-mode/overview" icon="bird" color="#7CE38B" iconType="light">
    Let others follow along your screen
  </Card>

  <Card title="Huddle" href="/realtime-collaboration/huddle/overview" icon="headphones" color="#7CE38B" iconType="light">
    Hop on a group call with everyone
  </Card>

  <Card title="Live Selection" href="/realtime-collaboration/live-selection/overview" icon="square-dashed" color="#7CE38B" iconType="light">
    See what others are editing
  </Card>
</CardGroup>

## Advanced

<CardGroup cols={2}>
  <Card title="Webhooks" href="/webhooks/overview" icon="webhook" color="#CEA5FB" iconType="light">
    Call a webhook when a comment is added
  </Card>

  <Card title="Email Notifications" href="/notifications/email/overview" icon="envelope" color="#CEA5FB" iconType="light">
    Set up email notifications
  </Card>

  <Card title="REST APIs" href="/api-reference/rest-apis" icon="server" color="#CEA5FB" iconType="light">
    Retrieve or modify data
  </Card>

  <Card title="UI Customization" href="/ui-customization/overview" icon="paintbrush" color="#CEA5FB" iconType="light">
    Fully customize Velt Components
  </Card>
</CardGroup>


# Quickstart

Quickstart for React. For other frameworks like `vue`, `angular`, `svelte`, `vanilla js` etc. check out the setup guide.

<Steps titleSize="h2">
  <Step title="Create a React app">
    Create a new React app [using any method](https://react.dev/learn/start-a-new-react-project) you prefer.

    {/* ```bash Terminal
    npx create-next-app@latest
    ``` */}
  </Step>

  <Step title="Install the Velt React package onto your app">
    ```bash Terminal
    cd my-app && npm install @veltdev/react
    ```
  </Step>

  <Step title="Install types (optional)">
    If you're using TypeScript, you can install the types package.

    ```bash Terminal
    npm install --save-dev @veltdev/types
    ```
  </Step>

  <Step title="Grab your Velt API Key">
    Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key

    <Frame>
      ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-api-key.png)
    </Frame>
  </Step>

  <Step title="Safelist your domain">
    In the Velt console, add the URL where your app is deployed to the list of Managed Domains.

    <Frame>
      ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-add-website.png)
    </Frame>
  </Step>

  <Step title="Configure the VeltProvider">
    In **App.js**, add the `VeltProvider` component to the root of your app with your Velt API Key.

    ```js App.js
    <VeltProvider apiKey="YOUR_API_KEY">
      <YourAuthComponent/>
      <YourDocument/>
    </VeltProvider>
    ```
  </Step>

  <Step title="Identify your user">
    In **YourAuthComponent.js**, use the `useIdentify()` hook from the Velt SDK to identify your user.

    ```js YourAuthComponent.js
    import { useIdentify } from '@veltdev/react';

    useIdentify(user)
    ```

    <Warning>Make sure to call `useIdentify()` within a child component of the Velt Provider. Otherwise, it will not work.</Warning>
  </Step>

  <Step title="Set the Document ID">
    In **YourDocument.js**, use the `useSetDocumentId()` hook from the Velt SDK to set the Document ID.

    ```js YourDocument.js
    import { useSetDocumentId } from '@veltdev/react';

    useSetDocumentId("my-document-id")
    ```
  </Step>

  <Step title="Add the VeltComments, VeltCommentTool and VeltPresence components">
    In **App.js**, add `VeltComments` to enable the `Comments` functionality.

    ```js App.js
    <VeltProvider apiKey="YOUR_API_KEY">
      <VeltComments/>
      <YourAuthComponent/>
      <YourDocument/>
    </VeltProvider>
    ```

    In **YourDocument.js**, add the `VeltCommentTool` and `VeltPresence` components to test out the `Comments` and `Presence` functionality.

    ```js YourDocument.js
    <div>
      <VeltPresence/>
      <VeltCommentTool/>
    </div>
    ```
  </Step>

  <Step title="Test out the Presence and Comments functionality">
    ### Comments

    *   Click the `VeltCommentTool` button, then hover over any element on the page to leave a comment.
    *   Click the `VeltCommentTool` button, then try to draw a box on the page to leave a comment.
    *   You can also highlight any text to leave a comment.

    ### Presence

    *   Open two browser tabs side by side with one in Incognito mode. You should see a bubble showing the other browser's profile avatar pop up.
  </Step>

  <Step title="Need an example?">
    Fork this repo if you want all the steps above done for you. You will still need to use your own Velt API Key.

    [Github Repo](https://github.com/Snippyly-Docs/velt-quickstart-hooks-demo)

    [CodeSandBox Link](https://codesandbox.io/embed/github/Snippyly-Docs/velt-quickstart-hooks-demo?fontsize=14\&hidenavigation=1\&module=%2Fsrc%2FApp.tsx\&theme=dark\&view=editor)

    [View Demo in Larger Window](https://velt-quickstart-hooks-demo.vercel.app/)

    [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/Snippyly-Docs/velt-quickstart-hooks-demo)

    <Frame>
      <iframe src="https://velt-quickstart-hooks-demo.vercel.app/" className="w-full" scrolling="no" height="500px" />
    </Frame>
  </Step>

  <Step title="Need more details on how to integrate this into an existing app?">
    Check out this guide on [how to set up Velt with your existing app](/get-started/setup/install)
  </Step>
</Steps>

<RequestExample>
  ```jsx App.js
  import { VeltProvider, VeltComments, VeltPresence } from '@veltdev/react';
  import YourAuthComponent from './YourAuthComponent';
  import YourDocument from './YourDocument';

  export default function App() {

    return (
      <VeltProvider apiKey="YOUR_API_KEY">
        <VeltComments/>
        <VeltPresence/>
        <YourAuthComponent/>
        <YourDocument/>
      </VeltProvider>
    );
  }
  ```

  ```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 <div>User: {user?.userId}</div>;
  }
  ```

  ```jsx YourDocument.js
  import {  useSetDocumentId, VeltCommentTool, VeltPresence } from '@veltdev/react';
  import { useEffect, useState } from 'react';

  export default function YourDocument() {

    useSetDocumentId('my-document-id')

    return (
      <div>
        <VeltCommentTool/>
      </div>
      
    );
  }
  ```
</RequestExample>


# Advanced Setup Options



<Tabs>
  <Tab title="React / Next.js with Hooks">
    ## 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**.

    <Tip> If a **Document** is like a house, a **Location** is like a room within the house. </Tip>

    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

    To detect if the Velt SDK is initialized, subscribe using the following method:

    ```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]);
    }

    ```
  </Tab>

  <Tab title="React / Next.js">
    ## 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**.

    <Tip> If a **Document** is like a house, a **Location** is like a room within the house. </Tip>

    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

    To detect if the Velt SDK is initialized, subscribe using the following method:

    ```jsx
    let subscription = client.getVeltInitState().subscribe((veltInitState: boolean | undefined) => {
    	console.log('Velt Init State:', veltInitState);
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="HTML">
    ## 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**.

    <Tip> If a **Document** is like a house, a **Location** is like a room within the house. </Tip>

    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

    To detect if the Velt SDK is initialized, subscribe using the following method:

    ```jsx
    let subscription = Velt.getVeltInitState().subscribe((veltInitState: boolean | undefined) => {
    	console.log('Velt Init State:', veltInitState);
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Angular">
    ## 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**.

    <Tip> If a **Document** is like a house, a **Location** is like a room within the house. </Tip>

    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

    To detect if the Velt SDK is initialized, subscribe using the following method:

    ```jsx
    let subscription = this.client.getVeltInitState().subscribe((veltInitState: boolean | undefined) => {
    	console.log('Velt Init State:', veltInitState);
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>

  <Tab title="Vue.js">
    ## 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**.

    <Tip> If a **Document** is like a house, a **Location** is like a room within the house. </Tip>

    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

    To detect if the Velt SDK is initialized, subscribe using the following method:

    ```jsx
    let subscription = client.getVeltInitState().subscribe((veltInitState: boolean | undefined) => {
    	console.log('Velt Init State:', veltInitState);
    });
    ```

    To unsubscribe from the subscription:

    ```jsx
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>


# 2. Authenticate

Autheticate your logged in users with the SDK.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that handles authentication.</Info>

    <Steps titleSize="h2">
      <Step title="Import the useIdentify Hook">
        Import the `useIdentify` hook.

        ```js
          import { useIdentify } from '@veltdev/react'
        ```
      </Step>

      <Step title="Fetch relevant user info">
        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,
            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.
            organizationId: organizationId // this is the organization id the user belongs to
          };
        ```

        <Info>
          To enable `@mention` in the comments, you need to pass the user's contacts. Learn more about how it works [here](https://docs.velt.dev/users/add-user-contacts/setup).
        </Info>
      </Step>

      <Step title=" Pass the User object to the SDK">
        Call the `useIdentify()` hook and pass in the Velt `User` object.

        ```js
          useIdentify(user);
        ```

        <Info>The `useIdentify()` method is asynchronous.</Info>
        <Warning>You must call `useIdentify` within a child component of the `VeltProvider`, or else it will not work.</Warning>
        <Info>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. </Info>
      </Step>

      <Step title="(Optional) - Add JWT Tokens for additional security">
        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,
          });
        ```

        <Info> We will use the `email` address and `organizationId` passed in the identify call to validate the user later to prevent unauthorized access. </Info>

        See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK.
      </Step>

      <Step title="(Optional) - Force re-login user on identify call">
        `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
        });

        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="React / Next.js">
    <Note>We recommend following the setup guide that uses `React / Next.js with Hooks` for a cleaner experience.</Note>
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that handles authentication.</Info>

    <Steps titleSize="h2">
      <Step title="Get the Velt client">
        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();
        ```
      </Step>

      <Step title="Create a useEffect hook">
        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]);
        ```
      </Step>

      <Step title="Fetch relevant user info">
        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,
            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.
            organizationId: organizationId // this is the organization id the user belongs to
          };
        ```

        <Info>
          To enable `@mention` in the comments, you need to pass the user's contacts. Learn more about how it works [here](https://docs.velt.dev/users/add-user-contacts/setup).
        </Info>
      </Step>

      <Step title=" Pass the User object to the SDK">
        Call the `identify()` method and pass in the Velt `User` object.

        ```js
          await client.identify(user);
        ```

        <Info>The `client.identify()` method is asynchronous.</Info>
        <Warning>You must call `client.identify` within a child component of the `VeltProvider`, or else it will not work.</Warning>
        <Info>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. </Info>
      </Step>

      <Step title="(Optional) - Add JWT Tokens for additional security">
        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,
          });
        ```

        <Info> We will use the `email` address and `organizationId` passed in the identify call to validate the user later to prevent unauthorized access. </Info>

        See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK.
      </Step>

      <Step title="(Optional) - Force re-login user on identify call">
        `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
        });

        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML">
    <Steps titleSize="h2">
      <Step title="Fetch relevant user info">
        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,
            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.
            organizationId: organizationId // this is the organization id the user belongs to
          };
        ```

        <Info>
          To enable `@mention` in the comments, you need to pass the `User's` contacts. Learn more about how it works [here](https://docs.velt.dev/users/add-user-contacts/setup).
        </Info>
      </Step>

      <Step title="Identify the Logged In User">
        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)
        ```

        <Info>The `Velt.identify()` method is asynchronous</Info>
        <Warning>You must call `client.identify` within a child component of the `VeltProvider`, or else it will not work.</Warning>
        <Info>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. </Info>
      </Step>

      <Step title="(Optional) - Add JWT Tokens for additional security">
        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,
        });
        ```

        <Info> We will use the `email` address and `organizationId` passed in the identify call to validate the user later to prevent unauthorized access. </Info>

        See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK.
      </Step>

      <Step title="(Optional) - Force re-login user on identify call">
        `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
        });

        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Angular">
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that handles authentication.</Info>

    <Steps titleSize="h2">
      <Step title="Get User Info">
        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,
            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.
            organizationId: organizationId // this is the organization id the user belongs to
          };
        ```
      </Step>

      <Step title="Identify your user">
        ```jsx
        this.client.identify(user);
        ```

        <Info>The `this.client.identify()` method is asynchronous.</Info>
        <Info>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. </Info>
      </Step>

      <Step title="(Optional) - Add JWT Tokens for additional security">
        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,
        });
        ```

        <Info> We will use the `email` address and `organizationId` passed in the identify call to validate the user later to prevent unauthorized access. </Info>

        See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK.
      </Step>

      <Step title="(Optional) - Force re-login user on identify call">
        `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
        });

        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Vue.js">
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that handles authentication.</Info>

    <Steps titleSize="h2">
      <Step title="Get User Info">
        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,
            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.
            organizationId: organizationId // this is the organization id the user belongs to
          };
        ```
      </Step>

      <Step title="Identify your user">
        ```jsx
        client.identify(user);
        ```

        <Info>The `client.identify()` method is asynchronous.</Info>
        <Warning>You must call `client.identify()` within a child component of the `VeltProvider`, or else it will not work.</Warning>

        <Info>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. </Info>
      </Step>

      <Step title="(Optional) - Add JWT Tokens for additional security">
        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,
        });
        ```

        <Info> We will use the `email` address and `organizationId` passed in the identify call to validate the user later to prevent unauthorized access. </Info>

        See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK.
      </Step>

      <Step title="(Optional) - Force re-login user on identify call">
        `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
        });

        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```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",
        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.
        organizationId: organizationId
      }
    }

    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,
      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.
      organizationId: organizationId // this is the organization id the user belongs to
    };

    //3) Pass the user object to the SDK
    useIdentify(user)
        

    return (
      <div>
      // Your auth component template
      </div>
    );
  }

  ```

  ```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",
        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.
        organizationId: organizationId
      }
    }

    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,
            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.
            organizationId: organizationId // this is the organization id the user belongs to
          };

          //4) Pass the user object to the SDK
          await client.identify(user)
        }
      }
      initVelt().catch(console.error)
    }, [client, yourAuthenticatedUser]);

    return (
      <div>
      // Your auth component template
      </div>
    );
  }

  ```

  ```html HTML

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");
          if (Velt) {
            // You need to pass these fields about your logged in user to us.
            const yourLoggedInUser = {
              userId: '9snk30djks9e4mndk',
              name: 'John Doe',
              photoUrl: 'https://i.pravatar.cc/300', //(optional)
              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.
              email: 'jdoe@xyz.com',
              plan: 'free', //(optional)
              organizationId: 'organizationId123' //(optional) If you want to categorize the user into an organization
            }
            // 1) Identify the Logged In User
            await Velt.identify(yourLoggedInUser)
          }       
        }
      </script>
    </head>
    <body>
      
    </body>
  </html>
  ```

  ```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,
          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.
          organizationId: 'organizationId123' //(optional) If you want to categorize the user into an organization
        }; // Your user object here 
        this.client.identify(user);
      }
    }
  }
  ```

  ```html Vue.js
  <script>
  import Vue from "vue";
  import { initVelt } from "@veltdev/client";

  var client;

  const initializeVelt = async () => {
    client = await initVelt("YOUR_APIKEY");
    setUser();
  }


  const setUser = () => {
    if (client) {
      const user = {
        userId: uid,
        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.
        organizationId: 'organizationId123' //(optional) If you want to categorize the user into an organization

      }; // Your user object here
      client.identify(user);
    }
  }

  export default Vue.extend({
    name: "App",
    mounted() {
      initializeVelt();
    },
  });
  </script>
  ```
</RequestExample>


# 3. 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.

<Warning>The SDK will not work without this call.</Warning>

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

<Tabs>
  <Tab title="React / Next.js with Hooks">
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that represents your document.</Info>

    ```jsx
    import { useSetDocument } from '@veltdev/react';
    useSetDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>

  <Tab title="React / Next.js">
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that represents your document.</Info>

    ```jsx
    const { client } = useVeltClient();

    useEffect(() => {
        if (client) {
            client.setDocument('unique-document-id', {documentName: 'Document Name'});
        }
    }, [client]);
    ```
  </Tab>

  <Tab title="HTML">
    ```jsx
    if(Velt){
        Velt.setDocument('unique-document-id', {documentName: 'Document Name'});
    }
    ```
  </Tab>

  <Tab title="Angular">
    ```jsx
    if (this.client) {
      this.client.setDocument('unique-document-id', {documentName: 'Document Name'});
    }
    ```
  </Tab>

  <Tab title="Vue.js">
    ```jsx
    if (client) {
      client.setDocument('unique-document-id', {documentName: 'Document Name'});
    }
    ```
  </Tab>
</Tabs>

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

<Tabs>
  <Tab title="React / Next.js with Hooks">
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that represents your document.</Info>

    ```jsx
    import { useSetDocument } from '@veltdev/react';
    useSetDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'});
    ```
  </Tab>

  <Tab title="React / Next.js">
    <Warning>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.</Warning>
    <Info>Realistically, these steps should be done inside your component that represents your document.</Info>

    ```jsx
    const { client } = useVeltClient();

    useEffect(() => {
        if (client) {
            client.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'});
        }
    }, [client]);
    ```
  </Tab>

  <Tab title="HTML">
    ```jsx
    if(Velt){
        Velt.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'});
    }
    ```
  </Tab>

  <Tab title="Angular">
    ```jsx
    if (this.client) {
      this.client.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'});
    }
    ```
  </Tab>

  <Tab title="Vue.js">
    ```jsx
    if (client) {
      client.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'});
    }
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```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 (
      <div>
        //your document template - add Velt Components here
      </div>
      
    );
  }
  ```

  ```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 (
      <div>
        //your document template - add Velt Components here
      </div>
      
    );
  }
  ```

  ```html HTML

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          if (Velt) {
            await Velt.init("YOUR_VELT_API_KEY");
            Velt.setDocument('CUSTOM_DOCUMENT_ID', {documentName: 'Document Name'});
          }       
        }
      </script>
    </head>
    <body>
      //your document template - add Velt Components here
    </body>
  </html>
  ```

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

  <div>
    // to add comments (ideally add to root component ex: AppComponent)
    <velt-comments></velt-comments>

    // comment tool
    <velt-comment-tool></velt-comment-tool>

    // comment sidebar
    <velt-comments-sidebar></velt-comments-sidebar>

    // Add other feature tags ...
  </div>

  ```

  ```html Vue.js
  <template>
  	... your html
  	<velt-comments></velt-comments>
  <velt-presence></velt-presence>
    ... Add other velt elements as required
  </template>

  <script>
  import Vue from "vue";
  import { initVelt } from "@veltdev/client";

  var client;

  const initializeVelt = async () => {
    client = await initVelt("YOUR_APIKEY");
    setDocument();
  }

  const setDocument = () => {
    if (client) {
      client.setDocument("YOUR_DOCUMENT_ID", { documentName: "Document Name" });
    }
  }


  export default Vue.extend({
    name: "App",
    mounted() {
      initializeVelt();
    },
  });
  </script>
  ```
</RequestExample>


# 1. Install

Steps to integrate Velt into an existing app

<Tabs>
  <Tab title="React / Next.js with Hooks">
    <Steps titleSize="h2">
      <Step title="Install React package">
        npm:

        ```bash
        npm install @veltdev/react
        ```

        yarn:

        ```bash
        $ yarn add @veltdev/react
        ```
      </Step>

      <Step title="Install types (optional)">
        If you're using TypeScript, you can install the types package.

        ```bash
        npm install --save-dev @veltdev/types
        ```
      </Step>

      <Step title="Grab your Velt API Key">
        Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-api-key.png)
        </Frame>
      </Step>

      <Step title="Safelist your domain">
        In the Velt console, add the URL where your app is deployed to the list of Managed Domains.

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-add-website.png)
        </Frame>
      </Step>

      <Step title="Add the VeltProvider">
        Add the VeltProvider component to the root of your app.

        Add your Velt API key.

        ```js
        import { VeltProvider } from '@veltdev/react';
        ```

        ```js
        <VeltProvider apiKey="YOUR_API_KEY">
          <YourRootComponent/>
        </VeltProvider>
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="React / Next.js">
    <Note>We recommend following the setup guide that uses `React / Next.js with Hooks` for a cleaner experience.</Note>

    <Steps titleSize="h2">
      <Step title="Install React package">
        npm:

        ```bash
        npm install @veltdev/react
        ```

        yarn:

        ```bash
        $ yarn add @veltdev/react
        ```
      </Step>

      <Step title="Install types (optional)">
        If you're using TypeScript, you can install the types package.

        ```bash
        npm install --save-dev @veltdev/types
        ```
      </Step>

      <Step title="Grab your Velt API Key">
        Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-api-key.png)
        </Frame>
      </Step>

      <Step title="Safelist your domain">
        In the Velt console, add the URL where your app is deployed to the list of Managed Domains.

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-add-website.png)
        </Frame>
      </Step>

      <Step title="Add the VeltProvider">
        Add the VeltProvider component to the root of your app.

        Add your Velt API key.

        ```js
        import { VeltProvider } from '@veltdev/react';
        ```

        ```js
        <VeltProvider apiKey="YOUR_API_KEY">
          <YourRootComponent/>
        </VeltProvider>
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML">
    <Steps titleSize="h2">
      <Step title="Grab your Velt API Key">
        Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-api-key.png)
        </Frame>
      </Step>

      <Step title="Safelist your domain">
        In the Velt console, add the URL where your app is deployed to the list of Managed Domains.

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-add-website.png)
        </Frame>
      </Step>

      <Step title="Import the Velt Script tag">
        ```html
        <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
        ```
      </Step>

      <Step title="Initialize with your API Key">
        Put this in your root app script:

        ```js
        async function loadVelt() {
            await Velt.init("YOUR_VELT_API_KEY");
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Angular">
    <Steps>
      <Step title="Install client library">
        ```jsx
        npm i @veltdev/client
        ```
      </Step>

      <Step title="Install types library (optional)">
        If you are using Typescript, install the types library:

        ```jsx
        npm i @veltdev/types --save-dev
        ```
      </Step>

      <Step title="Grab your Velt API Key">
        Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-api-key.png)
        </Frame>
      </Step>

      <Step title="Safelist your domain">
        In the Velt console, add the URL where your app is deployed to the list of Managed Domains.

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-add-website.png)
        </Frame>
      </Step>

      <Step title="Add Custom Elements Schema in App Module">
        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 { }
        ```
      </Step>

      <Step title="Get the Velt Client ">
        ```jsx
        import { initVelt } from '@veltdev/client';
        ```

        ```jsx
        this.client = await initVelt('YOUR_APIKEY');
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Vue.js">
    <Steps>
      <Step title="Install client library">
        ```jsx
        npm i @veltdev/client
        ```
      </Step>

      <Step title="Install types library (optional)">
        If you are using Typescript, install the types library:

        ```jsx
        npm i @veltdev/types --save-dev
        ```
      </Step>

      <Step title="Grab your Velt API Key">
        Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-api-key.png)
        </Frame>
      </Step>

      <Step title="Safelist your domain">
        In the Velt console, add the URL where your app is deployed to the list of Managed Domains.

        <Frame>
          ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/velt-console-add-website.png)
        </Frame>
      </Step>

      <Step title="Allow Velt Elements in Main.js">
        In main.js, add the following code to allow Velt elements in your Vue app:

        ```html
        Vue.config.ignoredElements = [
          /velt-*/
        ]
        ```
      </Step>

      <Step title="Get the Velt Client ">
        ```jsx
        import { initVelt } from '@veltdev/client';
        ```

        ```jsx
        client = await initVelt("YOUR_APIKEY");
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js with Hooks
  import { VeltProvider } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="YOUR_API_KEY">
        <YourRootComponent/>
      </VeltProvider>
    );
  }
  ```

  ```jsx React / Next.js
  import { VeltProvider } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="YOUR_API_KEY">
        <YourRootComponent/>
      </VeltProvider>
    );
  }
  ```

  ```html HTML

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");
        }
      </script>
    </head>
    <body>
      
    </body>
  </html>
  ```

  ```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 { }
  ```

  ```html Vue.js
  Vue.config.ignoredElements = [
    /velt-*/
  ]
  ```
</RequestExample>


# AG Grid



## How to add Velt attributes to AG Grid cells?

Some Velt features like live selection require adding Velt specific attributes to the cell elements. Here's how you can do it:

1.  In your AG Grid column definitions, use the `cell renderer` property to customize the cell rendering.
2.  Within the `cell renderer`, add the necessary Velt attributes to the cell element.

Here's a code sample that shows how to add the `data-velt-live-selection-enabled` attribute and other required attributes to AG Grid cell div tags:

```jsx
colDefs: ColDef[] = [
  {
    field: "FIELD_NAME",
    cellRenderer: (params: any) => {
      // Let AG Grid render the default cell, then modify the outer div
      setTimeout(() => {
        const cellElement = params.eGridCell;
        // Add Velt attributes to the parent cell div
        cellElement.setAttribute('data-velt-live-selection-enabled', 'true');
        // Add other Velt attributes as required
      }, 0);  // Timeout to wait for the DOM to be ready
      return params.value;  // Use the default renderer, which is the text value
    },
    editable: true, // Set to true if the column is editable
  },
];
```


# null



### Overview

Access Control is maintained at two levels:

1.  Organization level
2.  Document level

### 1. Organization Level

Here are some properties of Organization level access control:

*   Access to an Organization can be granted or revoked by adding or removing a User from an organization. A user can be added to multiple organizations but can only log in to one organization at a time.
*   By default all organization users have access to all organization data including documents, locations and user contacts.
*   Access to documents can be restricted by setting permissions at the document level. (more below)

### 2. Document Level

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/document-access.png)
Here are some properties of Organization level access control:

*   A document has three types of access:
    *   `public`: `default` Any user who logs into the given document id can access the document whether or not they are part of the organization or the document.
    *   `organizationPrivate`: Only all organization users have access to the document.
    *   `restricted`: Only users explicitly added to the document have access. Organization users not explicitly added will not have access.

*   Access to a Document can be granted or revoked by adding or removing a User from a document. Document level access overrides organization level access. Eg: if a document is restricted, only users explicitly added to the document will have access to it.

*   Access can also be granted or revoked by adding or removing organization user groups. `(coming soon)`

*   Organization users can access the entire Organization contact list in the Document.

*   Guest (Non-organization) users who have access to the document cannot access the Organization contact list. If you want to show some organization contacts to these guest users, then you need to explicitly add those contacts to the document.


# Set Document



A **Document** represents a shared collaborative space where users can interact. Documents live inside the Organization.

Documents contain:

*   All feature data (e.g., Comments, Presence, Cursors, etc.).
*   Locations
*   Users: These are different from Organization Users. (more details in Access Control section)

Users logged into the same `Document ID` can see each other's `Presence`, `Cursors`, `Comments` etc.

For example, in a slide presentation application, the entire slide deck is a document.

<Warning>Hooks currently do not support automatic change detection in variables.</Warning>

## 1. Setting a Document

*   Use this to initialize a Document.
*   It 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.

<Warning>The SDK will not work without this call.</Warning>

<Tabs>
  <Tab title="React / Next.js with Hooks">
    ```jsx
    useSetDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>

  <Tab title="React / Next.js">
    ```jsx
    const { client } = useVeltClient();

    useEffect(() => {
        if (client) {
            client.setDocument('unique-document-id', {documentName: 'Document Name'});
        }
    }, [client]);
    ```
  </Tab>

  <Tab title="HTML">
    ```jsx
    if(Velt){
        Velt.setDocument('unique-document-id', {documentName: 'Document Name'});
    }
    ```
  </Tab>

  <Tab title="Angular">
    ```jsx
    this.client.setDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>

  <Tab title="Vue.js">
    ```jsx
    client.setDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>
</Tabs>

## 2. Unset a Document

*   Use this to unset a Document.
*   For some parts of your app, you may not need Velt. In such cases, you can unset the document.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    ```jsx
    useUnsetDocumentId();
    ```
  </Tab>

  <Tab title="React / Next.js">
    ```jsx
    const { client } = useVeltClient();

    useEffect(() => {
        if (client) {
            client.unsetDocumentId();
        }
    }, [client]);
    ```
  </Tab>

  <Tab title="HTML">
    ```jsx
    Velt.unsetDocumentId();
    ```
  </Tab>

  <Tab title="Angular">
    ```jsx
    this.client.unsetDocumentId();
    ```
  </Tab>

  <Tab title="Vue.js">
    ```jsx
    client.unsetDocumentId();
    ```
  </Tab>
</Tabs>

## 3. Get Document Metadata

*   Use this to get the metadata of a Document.
*   This is useful when you want to display the document name in your app or any custom metadata that you have set.
*   This returns a subscription with [`DocumentMetadata`](/api-reference/models/DocumentMetadata) object.

<Tabs>
  {/* <Tab title="React / Next.js with Hooks">
  ```jsx
  useUnsetDocumentId();
  ```
  </Tab> */}

  <Tab title="React / Next.js">
    ```jsx
    const { client } = useVeltClient();

    useEffect(() => {
        if (client) {
            client.getDocumentMetadata().subscribe((documentMetadata) => {
                console.log("Current document metadata: ", documentMetadata);
            });
        }
    }, [client]);
    ```
  </Tab>

  <Tab title="HTML">
    ```jsx
    Velt.getDocumentMetadata().subscribe((documentMetadata) => {
        console.log("Current document metadata: ", documentMetadata);
    });
    ```
  </Tab>

  <Tab title="Angular">
    ```jsx
    this.client.getDocumentMetadata().subscribe((documentMetadata) => {
        console.log("Current document metadata: ", documentMetadata);
    });
    ```
  </Tab>

  <Tab title="Vue.js">
    ```jsx
    client.getDocumentMetadata().subscribe((documentMetadata) => {
        console.log("Current document metadata: ", documentMetadata);
    });
    ```
  </Tab>
</Tabs>

## 4. Access Documents from Other Organizations

*   By default, users can only access documents within their own organization.
*   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.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hook:**

    ```jsx
    useSetDocument(DOCUMENT_ID, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```

    **Using API:**

    ```jsx
    client.setDocument(DOCUMENT_ID, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    Velt.setDocument(DOCUMENT_ID, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```
  </Tab>
</Tabs>


# Use Multiple Locations at once



There are three main steps to adding multiple locations:

1.  Add a root location
2.  Add additional locations
3.  Bind elements containers to `locations`

<Steps>
  <Step title="Add a root location">
    <Tabs>
      <Tab title="React / Next.js with Hooks">
        ```jsx
        useSetDocument('some_document_id');

        useSetLocation({ 
          'id': 'locationRoot',
          'locationName': 'PageWithVideo',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
        })
        ```
      </Tab>

      <Tab title="React / Next.js">
        ```jsx
        client.setDocument('some_document_id');

        client.setLocation({ 
          'id': 'locationRoot',
          'locationName': 'PageWithVideo',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
        });
        ```
      </Tab>

      <Tab title="HTML">
        ```jsx
        Velt.setDocument('some_document_id');

        Velt.setLocation({ 
          'id': 'locationRoot',
          'locationName': 'PageWithVideo',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
        });
        ```
      </Tab>

      <Tab title="Angular">
        ```jsx
        this.client.setDocument('some_document_id');

        this.client.setLocation({ 
          'id': 'locationRoot',
          'locationName': 'PageWithVideo',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
        })
        ```
      </Tab>

      <Tab title="Vue.js">
        ```jsx
        client.setDocument('some_document_id');

        client.setLocation({ 
          'id': 'locationRoot',
          'locationName': 'PageWithVideo',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
        })
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Add additional locations">
    Add additional locations on the page by using set location with the `true` parameter:

    <Tabs>
      <Tab title="React / Next.js with Hooks">
        ```jsx
        useSetLocation({ 
          'id': 'locationId1',
          'locationName': 'Scene1LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '120'
        }, true)

        useSetLocation({
          'id': 'locationId2',
          'locationName': 'Scene2LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '50'
        }, true)

        useSetLocation({
          'id': 'locationId3',
          'locationName': 'Scene3LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '80'
        }, true)
        ```
      </Tab>

      <Tab title="React / Next.js">
        ```jsx
        client.setLocation({ 
          'id': 'locationId1',
          'locationName': 'Scene1LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '120'
        }, true)

        client.setLocation({
          'id': 'locationId2',
          'locationName': 'Scene2LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '50'
        }, true)

        client.setLocation({
          'id': 'locationId3',
          'locationName': 'Scene3LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '80'
        }, true)
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx
        Velt.setLocation({ 
          'id': 'locationId1',
          'locationName': 'Scene1LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'page': 'scene1',
          'videoFrame': '120'
        }, true)

        Velt.setLocation({
          'id': 'locationId2',
          'locationName': 'Scene2LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'page': 'scene2',
          'videoFrame': '50'
        }, true)

        Velt.setLocation({
          'id': 'locationId3',
          'locationName': 'Scene3LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'page': 'scene3',
          'videoFrame': '80'
        }, true)
        ```
      </Tab>

      <Tab title="Angular">
        ```jsx
        this.client.setLocation({ 
          'id': 'locationId1',
          'locationName': 'Scene1LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '120'
        }, true)

        this.client.setLocation({
          'id': 'locationId2',
          'locationName': 'Scene2LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '50'
        }, true)

        this.client.setLocation({
          'id': 'locationId3',
          'locationName': 'Scene3LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '80'
        }, true)
        ```
      </Tab>

      <Tab title="Vue.js">
        ```jsx
        client.setLocation({ 
          'id': 'locationId1',
          'locationName': 'Scene1LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '120'
        }, true)

        client.setLocation({
          'id': 'locationId2',
          'locationName': 'Scene2LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '50'
        }, true)

        client.setLocation({
          'id': 'locationId3',
          'locationName': 'Scene3LocationName',
          'version': {
        		'id': 'v1.0',
        		'name': 'Version Name'
        	},
          'videoFrame': '80'
        }, true)
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Bind element containers to locations">
    *   When you render multiple elements representing different locations on the same page,
        then you can bind each element container to the correct `location` by adding the `data-velt-location-id` attribute.

    *   This ensures that the comment added within the location is associated with the correct location.

    <Tabs>
      <Tab title="React / Next.js with Hooks">
        ```jsx
        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
        ```
      </Tab>

      <Tab title="React / Next.js">
        ```jsx
        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```jsx

        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
        ```
      </Tab>

      <Tab title="Angular">
        ```jsx
        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
        ```
      </Tab>

      <Tab title="Vue.js">
        ```jsx
        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
        ```
      </Tab>
    </Tabs>
  </Step>
</Steps>

<RequestExample>
  ```js React / Next.js with Hooks
  import { useSetDocument, useSetLocation } from '@veltdev/react';

  export default function YourDocument() {


    //Set Document ID
    useSetDocument('some_document_id');

    //Set Root Location
    useSetLocation({
        'id': 'locationId1',
        'locationName': 'Scene1LocationName',
        'version': {
          'id': 'v1.0',
          'name': 'Version Name'
        },
        'page': 'mainPage',
        'videoFrame': '120'
        // You can keep adding more field to make the location very specific.
        // The field names can be anything.
    })

    //Add another Location
    useSetLocation({
        'id': 'locationId2',
        'locationName': 'Scene2LocationName',
        'version': {
          'id': 'v1.0',
          'name': 'Version Name'
        },
        'page': 'mainPage',
        'videoFrame': '240'
        // You can keep adding more field to make the location very specific.
        // The field names can be anything.
    },true)


    return (
      <div>
        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
      </div>
      
    );
  }
  ```

  ```js React / Next.js
  import { useVeltClient } from '@veltdev/react';
  import { useEffect, useState } from 'react';

  export default function YourDocument() {

    const { client } = useVeltClient();

    useEffect(() => {
      
      if (client) {
          //Set Document ID
          client.setDocument('some_document_id');

          //Set Root Location
          client.setLocation({
              'id': 'locationId1',
              'locationName': 'Scene1LocationName',
              'version': {
                'id': 'v1.0',
                'name': 'Version Name'
              },
              'page': 'mainPage',
              'videoFrame': '120'
              // You can keep adding more field to make the location very specific.
              // The field names can be anything.
          })

          //Add another Location
          client.setLocation({
              'id': 'locationId2',
              'locationName': 'Scene2LocationName',
              'version': {
                'id': 'v1.0',
                'name': 'Version Name'
              },
              'page': 'mainPage',
              'videoFrame': '240'
              // You can keep adding more field to make the location very specific.
              // The field names can be anything.
          },true)
      }
    }, [client]);

    return (
      <div>
        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
      </div>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");

          if (Velt) {
            //Set Document ID
            Velt.setDocument('some_document_id'); 

            // Set Root Location
            Velt.setLocation({ 
              'id': 'locationId1',
              'locationName': 'Scene1LocationName',
              'version': {
                'id': 'v1.0',
                'name': 'Version Name'
              },
              'page': 'mainPage',
              'videoFrame': '120'
              // You can keep adding more field to make the location very specific.
              // The field names can be anything.
            })

            //Add another Location
            Velt.setLocation({
                'id': 'locationId2',
                'locationName': 'Scene2LocationName',
                'version': {
                  'id': 'v1.0',
                  'name': 'Version Name'
                },
                'page': 'mainPage',
                'videoFrame': '240'
                // You can keep adding more field to make the location very specific.
                // The field names can be anything.
            },true)
          }
        }
      </script>
    </head>
    <body>
      <div>
        <div class="page">
          <div id="location1-id" data-velt-location-id="location1-id">
            <div class="card">
              // any content
            </div>
          </div>
          <div id="location2-id" data-velt-location-id="location2-id">
            <div class="card">
              // any content
            </div>
          </div>
        </div>
      </div>
    </body>
  </html>
  ```

  ```js 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 id in velt
    setDocument() {
      if (this.client) {
        //Set Document ID
        this.client.setDocument('some_document_id');

        //Set Root Location
        this.client.setLocation({
            'id': 'locationId1',
            'locationName': 'Scene1LocationName',
            'version': {
              'id': 'v1.0',
              'name': 'Version Name'
            },
            'page': 'mainPage',
            'videoFrame': '120'
            // You can keep adding more field to make the location very specific.
            // The field names can be anything.
        })

        //Add another Location
        this.client.setLocation({
            'id': 'locationId2',
            'locationName': 'Scene2LocationName',
            'version': {
              'id': 'v1.0',
              'name': 'Version Name'
            },
            'page': 'mainPage',
            'videoFrame': '240'
            // You can keep adding more field to make the location very specific.
            // The field names can be anything.
        },true)
      }
    }
  }

  //                 Your HTML File                   //

  <div>
    <div class="page">
      <div id="location1-id" data-velt-location-id="location1-id">
        <div class="card">
          // any content
        </div>
      </div>
      <div id="location2-id" data-velt-location-id="location2-id">
        <div class="card">
          // any content
        </div>
      </div>
    </div>
  </div>
  ```

  ```js Vue.js
  <template>
    <div>
      <div class="page">
        <div id="location1-id" data-velt-location-id="location1-id">
          <div class="card">
            // any content
          </div>
        </div>
        <div id="location2-id" data-velt-location-id="location2-id">
          <div class="card">
            // any content
          </div>
        </div>
      </div>
    </div>
  </template>

  <script>
  import Vue from "vue";
  import { initVelt } from "@veltdev/client";

  var client;

    // Initialize velt sdk
    const initializeVelt = async () => {
      client = await initVelt("YOUR_APIKEY");
      setDocument();
    }

    const setDocument = () => {
      if (client) {
        client.setDocument("YOUR_DOCUMENT_ID");
      }
    }

    //Set Root Location
    client.setLocation({
        'id': 'locationId1',
        'locationName': 'Scene1LocationName',
        'version': {
          'id': 'v1.0',
          'name': 'Version Name'
        },
        'page': 'mainPage',
        'videoFrame': '120'
        // You can keep adding more field to make the location very specific.
        // The field names can be anything.
    })

    //Add another Location
    client.setLocation({
        'id': 'locationId2',
        'locationName': 'Scene2LocationName',
        'version': {
          'id': 'v1.0',
          'name': 'Version Name'
        },
        'page': 'mainPage',
        'videoFrame': '240'
        // You can keep adding more field to make the location very specific.
        // The field names can be anything.
    })


    export default Vue.extend({
      name: "App",
      mounted() {
        initializeVelt();
      },
    });
  </script>
  ```
</RequestExample>


# Remove Locations



<Tabs>
  <Tab title="React / Next.js">
    <Steps>
      <Step title="Removing all Locations">
        To remove all locations, use the `client.removeLocation()` method.

        ```jsx
        client.removeLocation()
        ```
      </Step>

      <Step title="Removing specific Locations">
        If you have added multiple locations and only want to remove one of them, you can remove it by using `client.removeLocation()` and by passing in the exact location object you want to remove.

        ```jsx
        // remove specific location
        const locationToRemove = {
        	// your custom location object
        }
        client.removeLocation(locationToRemove);
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML">
    <Steps>
      <Step title="Removing all Locations">
        To remove all locations, use the `client.removeLocation()` method.

        ```jsx
        Velt.removeLocation()
        ```
      </Step>

      <Step title="Removing specific Locations">
        If you have added multiple locations and only want to remove one of them, you can remove it by using `client.removeLocation()` and by passing in the exact location object you want to remove.

        ```jsx
        // remove specific location
        const locationToRemove = {
        	// your custom location object
        }
        Velt.removeLocation(locationToRemove);
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Angular">
    <Steps>
      <Step title="Removing all Locations">
        To remove all locations, use the `client.removeLocation()` method.

        ```jsx
        this.client.removeLocation()
        ```
      </Step>

      <Step title="Removing specific Locations">
        If you have added multiple locations and only want to remove one of them, you can remove it by using `client.removeLocation()` and by passing in the exact location object you want to remove.

        ```jsx
        // remove specific location
        const locationToRemove = {
        	// your custom location object
        }
        this.client.removeLocation(locationToRemove);
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Vue.js">
    <Steps>
      <Step title="Removing all Locations">
        To remove all locations, use the `client.removeLocation()` method.

        ```jsx
        client.removeLocation()
        ```
      </Step>

      <Step title="Removing specific Locations">
        If you have added multiple locations and only want to remove one of them, you can remove it by using `client.removeLocation()` and by passing in the exact location object you want to remove.

        ```jsx
        // remove specific location
        const locationToRemove = {
        	// your custom location object
        }
        client.removeLocation(locationToRemove);
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  //Set Location
  client.setLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName'
  })

  //Add another Location
  client.setLocation({
  	'id': 'locationId2',
  	'locationName': 'Scene2LocationName'
  },true)

  //Remove first Location
  client.removeLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName'
  });
  ```

  ```jsx HTML
  //Set Location
  Velt.setLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName',
  })

  //Add another Location
  Velt.setLocation({
  	'id': 'locationId2',
  	'locationName': 'Scene2LocationName'
  },true)

  //Remove first Location
  Velt.removeLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName'
  });
  ```

  ```jsx Angular
  //Set Location
  this.client.setLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName'
  })

  //Add another Location
  this.client.setLocation({
  	'id': 'locationId2',
  	'locationName': 'Scene2LocationName'
  },true)

  //Remove first Location
  this.client.removeLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName'
  });
  ```

  ```jsx Vue.js
  //Set Location
  client.setLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName'
  })

  //Add another Location
  client.setLocation({
  	'id': 'locationId2',
  	'locationName': 'Scene2LocationName'
  },true)

  //Remove first Location
  client.removeLocation({
  	'id': 'locationId1',
  	'locationName': 'Scene1LocationName'
  });
  ```
</RequestExample>


# Set Location



<Tabs>
  <Tab title="React / Next.js with Hooks">
    <Warning>Hooks currently do not support automatic change detection in variables.</Warning>

    <Steps>
      <Step title="Import the useSetDocumentId and useSetLocation hooks">
        ```jsx
        import { useSetDocumentId, useSetLocation } from '@veltdev/react';
        ```
      </Step>

      <Step title="Set the document ID">
        ```js
        useSetDocumentId("my-document-id")
        ```
      </Step>

      <Step title="Set the Location">
        A **Location** can be described using any plain JSON object and can be set using the `useSetLocation` hook.

        This object could represent your app's pages, sections, versions, video frames, or data points on maps/charts etc.

        There are three important fields you should care about in your `location` object that are protected keywords:

        *   `id` - a unique ID to identify your location. It can be used by other methods to find or remove the location later. This field is required.
        *   `locationName` - a name to describe your location. It is used by other Velt components, such as the `VeltCommentsSideBar`, to label your location. This field is optional but highly recommended.
        *   `version` - an object that includes an `id` and `name` to mark the specific version of your location. This field is optional.

        ```jsx
        useSetLocation({
          'id': 'locationId1',
          'locationName': 'MainVideoPlayer',
          'page': 'mainPage',
          'version': {
            'id': 'v2.3',
            'name': 'Version Name'
          },
          'videoFrame': '120'
          // You can keep adding more field to make the location very specific.
          // The field names can be anything.
        })
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="React / Next.js">
    <Steps>
      <Step title="Import the Velt Client">
        ```jsx
        import { useVeltClient } from '@veltdev/react';
        ```

        ```jsx
        const { client } = useVeltClient();
        ```
      </Step>

      <Step title="Set the document ID">
        ```js
        useEffect(() => {
          if (client) {
            client.setDocumentId('my-unique-document-id')
          }
        }, [client]);
        ```
      </Step>

      <Step title="Set the Location">
        A **Location** can be described using any plain JSON object and can be set using the `client.setLocation()` method.

        This object could represent your app's pages, sections, versions, video frames, or data points on maps/charts etc.

        There are three important fields you should care about in your `location` object that are protected keywords:

        *   `id` - a unique ID to identify your location. It can be used by other methods to find or remove the location later. This field is required.
        *   `locationName` - a name to describe your location. It is used by other Velt components, such as the `VeltCommentsSideBar`, to label your location. This field is optional but highly recommended.
        *   `version` - an object that includes an `id` and `name` to mark the specific version of your location. This field is optional.

        ```jsx
        client.setLocation({
          'id': 'locationId1',
          'locationName': 'MainVideoPlayer',
          'page': 'mainPage',
          'version': {
            'id': 'v2.3',
            'name': 'Version Name'
          },
          'videoFrame': '120'
          // You can keep adding more field to make the location very specific.
          // The field names can be anything.
        })
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="HTML">
    <Steps>
      <Step title="Set the document ID">
        ```js
        if (Velt) {
          Velt.setDocumentId('my-unique-document-id')
        }
        ```
      </Step>

      <Step title="Set the Location">
        A **Location** can be described using any plain JSON object and can be set using the `client.setLocation()` method.

        This object could represent your app's pages, sections, versions, video frames, or data points on maps/charts etc.

        There are three important fields you should care about in your `location` object that are protected keywords:

        *   `id` - a unique ID to identify your location. It can be used by other methods to find or remove the location later. This field is required.
        *   `locationName` - a name to describe your location. It is used by other Velt components, such as the `VeltCommentsSideBar`, to label your location. This field is optional but highly recommended.
        *   `version` - an object that includes an `id` and `name` to mark the specific version of your location. This field is optional.

        ```jsx
        Velt.setLocation({
          'id': 'locationId1',
          'locationName': 'MainVideoPlayer',
          'page': 'mainPage',
          'version': {
            'id': 'v2.3',
            'name': 'Version Name'
          },
          'videoFrame': '120'
          // You can keep adding more field to make the location very specific.
          // The field names can be anything.
        })
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Angular">
    <Steps>
      <Step title="Import the Velt Client">
        ```jsx
        import { initVelt } from '@veltdev/client';
        ```

        ```jsx
        this.client = await initVelt('YOUR_APIKEY');
        ```
      </Step>

      <Step title="Set the document ID">
        ```js
        if (this.client) {
          this.client.setDocumentId('YOUR_DOCUMENT_ID');
        }
        ```
      </Step>

      <Step title="Set the Location">
        A **Location** can be described using any plain JSON object and can be set using the `this.client.setLocation()` method.

        This object could represent your app's pages, sections, versions, video frames, or data points on maps/charts etc.

        There are three important fields you should care about in your `location` object that are protected keywords:

        *   `id` - a unique ID to identify your location. It can be used by other methods to find or remove the location later. This field is required.
        *   `locationName` - a name to describe your location. It is used by other Velt components, such as the `VeltCommentsSideBar`, to label your location. This field is optional but highly recommended.
        *   `version` - an object that includes an `id` and `name` to mark the specific version of your location. This field is optional.

        ```jsx
        this.client.setLocation({
          'id': 'locationId1',
          'locationName': 'MainVideoPlayer',
          'page': 'mainPage',
          'version': {
            'id': 'v2.3',
            'name': 'Version Name'
          },
          'videoFrame': '120'
          // You can keep adding more field to make the location very specific.
          // The field names can be anything.
        })
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Vue.js">
    <Steps>
      <Step title="Import the Velt Client">
        ```jsx
        import { initVelt } from "@veltdev/client";
        ```

        ```jsx
        client = await initVelt("YOUR_APIKEY");
        ```
      </Step>

      <Step title="Set the document ID">
        ```js
        if (client) {
          client.setDocumentId("YOUR_DOCUMENT_ID");
        }
        ```
      </Step>

      <Step title="Set the Location">
        A **Location** can be described using any plain JSON object and can be set using the `client.setLocation()` method.

        This object could represent your app's pages, sections, versions, video frames, or data points on maps/charts etc.

        There are three important fields you should care about in your `location` object that are protected keywords:

        *   `id` - a unique ID to identify your location. It can be used by other methods to find or remove the location later. This field is required.
        *   `locationName` - a name to describe your location. It is used by other Velt components, such as the `VeltCommentsSideBar`, to label your location. This field is optional but highly recommended.
        *   `version` - an object that includes an `id` and `name` to mark the specific version of your location. This field is optional.

        ```jsx
        client.setLocation({
          'id': 'locationId1',
          'locationName': 'MainVideoPlayer',
          'page': 'mainPage',
          'version': {
            'id': 'v2.3',
            'name': 'Version Name'
          },
          'videoFrame': '120'
          // You can keep adding more field to make the location very specific.
          // The field names can be anything.
        })
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js with Hooks
  import { useSetDocumentId, useSetLocation } from '@veltdev/react';

  export default function YourDocument() {

    useSetDocumentId('some_document_id')

    useSetLocation({
      'id': 'locationId1',
      'locationName': 'Scene1LocationName',
      'page': 'mainPage',
      'version': {
        'id': 'v2.3',
        'name': 'Version Name'
      },
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
    })

    return (
      <div>
        //your document template
      </div>
      
    );
  }
  ```

  ```jsx React / Next.js
  import { useVeltClient } from '@veltdev/react';
  import { useEffect, useState } from 'react';

  export default function YourDocument() {

    const { client } = useVeltClient();

    useEffect(() => {
      
      if (client) {
          //Set Document ID
          client.setDocumentId('some_document_id');

          //Set Location
          client.setLocation({
              'id': 'locationId1',
              'locationName': 'Scene1LocationName',
              'page': 'mainPage',
              'version': {
                'id': 'v2.3',
                'name': 'Version Name'
              },
              'videoFrame': '120'
              // You can keep adding more field to make the location very specific.
              // The field names can be anything.
          })


      }
    }, [client]);

    return (
      <div>
        //your document template
      </div>
      
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Collaboration App</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>
      <script>
        async function loadVelt() {
          await Velt.init("YOUR_VELT_API_KEY");

          if (Velt) {
            //Set Document ID
            Velt.setDocumentId('some_document_id'); 

            // Set Location
            Velt.setLocation({ 
              'id': 'locationId1',
              'locationName': 'Scene1LocationName',
              'page': 'mainPage',
              'version': {
                'id': 'v2.3',
                'name': 'Version Name'
              },
              'videoFrame': '120'
              // You can keep adding more field to make the location very specific.
              // The field names can be anything.
            })

         
          }
        }
      </script>
    </head>
    <body>
      
    </body>
  </html>
  ```

  ```js 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.setDocumentId();
    }

    // set document id in velt
    setDocumentId() {
      if (this.client) {
        this.client.setDocumentId('YOUR_DOCUMENT_ID');
      }
    }

    //Set Location
    client.setLocation({
        'id': 'locationId1',
        'locationName': 'Scene1LocationName',
        'page': 'mainPage',
        'version': {
          'id': 'v2.3',
          'name': 'Version Name'
        },
        'videoFrame': '120'
        // You can keep adding more field to make the location very specific.
        // The field names can be anything.
    })

  }
  ```

  ```html Vue.js
  <script>
  import Vue from "vue";
  import { initVelt } from "@veltdev/client";

  var client;

  const initializeVelt = async () => {
    client = await initVelt("YOUR_APIKEY");
    setDocumentId();
  }

  const setDocumentId = () => {
    if (client) {
      client.setDocumentId("YOUR_DOCUMENT_ID");
    }
  }

  //Set Location
  client.setLocation({
      'id': 'locationId1',
      'locationName': 'Scene1LocationName',
      'page': 'mainPage',
      'version': {
        'id': 'v2.3',
        'name': 'Version Name'
      },
      'videoFrame': '120'
      // You can keep adding more field to make the location very specific.
      // The field names can be anything.
  })

  export default Vue.extend({
    name: "App",
    mounted() {
      initializeVelt();
    },
  });
  </script>
  ```
</RequestExample>


# null



### Create an Organization

#### Client side

When the user signs into an organization as described below,
if an organization is not present then it will be created automatically.

#### Server side

Using our REST APIs, you will be able to create an organization and also set metadata like name, description, etc.

### Add or Remove Users to an Organization to provision access

*   You will need to explicitly [add](/api-reference/rest-apis/users/add-users) or [delete](/api-reference/rest-apis/users/delete-users) users from the organization to provision or revoke access.
*   As users are added or removed in your app, you can use our API to sync that information on Velt as well.
*   Learn more about [User Management](/api-reference/rest-apis/users/add-users).

<Warning> If users are not added to the Organization, they will not be able to access the data inside it.</Warning>

### Sign in User into an Organization

*   In the [identify()](/get-started/setup/authenticate) method, set the `organizationId` and also add it to the [auth token](/security/jwt-tokens).
*   If you want the user to log into another organization, call the identify method again with the new organizationId and new auth token.

### Access Controls for Organizations

You can set up granular access controls for users within an organization. Learn more [here](/key-concepts/access-control/overview).


# null



## Overview

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/overview-concepts.png)

Velt uses Organizations, Documents, and Locations to organize data and users into the same shared spaces and subspaces, enabling granular access controls. The data hierarchy in Velt follows this structure:
Organization -> Documents -> Locations.

## Organizations

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/organizations.png)

An **Organization** is the top-level entity.

*   It contains documents, locations, and users.
*   Within an organization, you can create multiple documents, and each document can contain several locations.

<Info>Think of an `organization` as a Google Account belonging to a company (e.g., Company A). This account may have several `users` (Company A employees). A `document` will be any file created within the organization (e.g., document, spreadsheet, slides, etc.). A `location` will be any child section within the document (e.g., slide within a presentation).</Info>

## Documents

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/documents.png)

A **Document** represents a shared collaborative space where users can interact. Documents live inside the Organization.
Documents contain:

*   All feature data (e.g., Comments, Presence, Cursors, etc.).
*   Locations
*   Users: These are different from Organization Users. (more details in Access Control section)

Users logged into the same `Document ID` can see each other's `Presence`, `Cursors`, `Comments` etc.

For example, in a slide presentation application, the entire slide deck is a document.

## Locations

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/locations.png)

**Locations** are optional subspaces within a document, providing finer partitioning of data.
For instance:

*   In a slide presentation, the entire slide presentation will be a document each individual slide will be a location.
*   In a dashboard, the entire dashboard is a document but various filters applied will be locations;
*   In a video player, the entire video will be the document and timestamps will be locations.

<Tip> If a **Document** is like a house, a **Location** is like a room within the house. </Tip>

**Locations** are *completely optional*, you can opt to use them or not. If the complexity of your application does not require the use of **Locations**, you can use **Documents** by themselves to group your users together.

If you opt to use **Locations**, users in the same **Document** must also be in the same **Location** now to interact.

## Users

A `User` represents a person who has been authenticated with the Velt SDK.

Once a `User` has been authenticated, their profile can be seen within Velt's collaboration features.

For example in the `Comments` feature, the `User's` name is shown by their comment and in `@mentions`.

Additionally in the `Presence` and in `Cursors` features, the `User's` name is shown by their avatar bubble and mouse cursors.

There can be two categories of users:

1.  **Organization Users**: These belong to the organization and by default have access to organization documents and locations. You can control access to documents and locations at a more granular level for these users.
2.  **Guest Users**: For some use cases, you may want non-organization users to access and collaborate on a document within the organization. Using our access control features, you can provide access to guest users to only certain documents and user contacts within the organization.

### Contact List for @mention

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/mentions-users.png)

When the user is on a document, they can `@mention` other users. By default, the contact list for the @mention feature includes users from:

*   Organization users.
*   Guest users explicitly added to the current document.
*   Organization User Groups.
*   `@here`: This is a special group that includes only the users explicitly added on the document. This doesn't include organization users or organization user groups.

**Contact list is automatically updated:**

*   as users are added or removed from the organization or the document.
*   organization user groups are created or updated.

<Info>
  **Access Control:**
  Using the access control features, you can control which users are visible on the contact list on a given document.

  *   Organization users can access the entire Organization contact list on a given organization document.
  *   Guest (Non-organization) users who were granted access to an organization document cannot access the Organization contact list. If you want to show some organization contacts to these guest users, then you need to explicitly add them to the document.
</Info>

### Organization User Groups

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/mentions-groups.png)

You can create custom collection of users such as engineering, marketing etc to group organization users and manage access effectively.

*   This can be used to @mention a team group versus just individuals (just like in Slack).
*   This can also be used to provision access to documents.
*   Organization users can belong to multiple organization user groups.
*   Non-organization users can't be part of organization user groups.


# null



### Overview

When the user is on a document, they can `@mention` other users. By default, the contact list for the `@mention` feature includes users from:

*   Organization users.
*   Guest users explicitly added to the current document.
*   Organization User Groups.
*   `@here`: This is a special group that includes only the users explicitly added on the document. This doesn't include organization users or organization user groups.

**Contact list is automatically updated:**

*   as users are [added](/api-reference/rest-apis/users/add-users) or [deleted](/api-reference/rest-apis/users/delete-users) from the organization or the document.
*   users are [added](/api-reference/rest-apis/organization-user-groups/add-users-to-group) or [deleted](/api-reference/rest-apis/organization-user-groups/delete-users-from-group) from organization user groups.
*   organization user groups are [added](/api-reference/rest-apis/organization-user-groups/add-groups) or updated.

<Info>
  **Access Control:**
  Using the access control features, you can control which users are visible on the contact list on a given document.

  *   Organization users can access the entire Organization contact list on a given organization document.
  *   Guest (Non-organization) users who were granted access to an organization document cannot access the Organization contact list. If you want to show some organization contacts to these guest users, then you need to explicitly add them to the document.
</Info>


# null



### Overview

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/key-concepts/mentions-groups.png)
You can create custom collection of users such as engineering, marketing etc to group organization users and manage access effectively.

*   This can be used to @mention a team group versus just individuals (just like in Slack).
*   This can also be used to provision access to documents. (coming soon)
*   Organization users can belong to multiple organization user groups.
*   Non-organization users can't be part of organization user groups.

Learn more:

*   [Add Organization User Groups](/api-reference/rest-apis/organization-user-groups/add-groups)
*   [Add Users to Organization User Groups](/api-reference/rest-apis/organization-user-groups/add-users-to-group)
*   [Delete Users from Organization User Groups](/api-reference/rest-apis/organization-user-groups/delete-users-from-group)


# null



To sign in a user call the `identify()` method with the `userId` and `authToken` as described [here](get-started/setup/authenticate).

<Tip>Even though using JWT Auth token is optional, we recommend using it for additional security.</Tip>

Once a `User` has been authenticated, their profile can be seen within Velt's collaboration features.

For example in the Comments feature, the User's name is shown by their comment and in `@mentions`.

Additionally in the Presence and in Cursors features, the User's name is shown by their avatar bubble and mouse cursors.

### Sign in with force reset

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

Learn more [here](get-started/setup/authenticate).


# null



In a given session or browser tab, if you want to switch users,
you need to first signout the current user and then sign in using `identify` method again.
This will ensure we clean up the current user session and start a new session with the new user.

```jsx
client.signOutUser();
```


# Export Cord Data for Migration



<Warning>
  ### Note:

  *   These APIs have pagination built-in and return 1000 entries by default. Either extend the limit or loop over the pages to get all the data.
  *   Send data pulled from each API in a separate JSON file.
</Warning>

## Comments

Use the following Cord REST APIs to pull all the comments-related data and export it as a JSON file:

• [Threads](https://docs.cord.com/rest-apis/threads)

• [Messages](https://docs.cord.com/rest-apis/messages)

• [Users](https://docs.cord.com/rest-apis/users)

• [Groups](https://docs.cord.com/rest-apis/groups)

## Comment File Attachments

When you pull thread and message data using the above APIs, the file attachment URL is also present in the data. However, those URLs expire. You have two options for migration:

**Option 1**: You can use the URL to download the files and upload them to your cloud. Send us the new file attachment URLs in the following format in a JSON file:

Sample Format:

```jsx
[{
    "documentId": "<ID>",
    "userId": "<ID>",
    "messageId": "<ID>",
    "type": "file",
    "fileData": {
        "id": "<ID>",
        "type": "file",
        "name": "<FILE_NAME>",
        "url": "<URL>",
        "mimeType": "MIME_TYPE",
        "size": 6278949,
        "uploadStatus": "uploaded"
    },
    "fileUrl": "<URL>"
}]
```

**Option 2**: Schedule file migration date with us so you can pull the latest comments data, which will have fresh file access tokens. Then we can download/store it on our end, and update the URLs ourselves.

## Notifications

Given the ephemeral nature of notifications, we don't think you need to migrate them. However, if you do want us to migrate your notifications data, you could use this API to get the notifications data from Cord:

*   [Notifications](https://docs.cord.com/rest-apis/notifications)


# Overview



Cord has shut down their service. We are providing a migration path for all the Cord users to migrate to Velt.

## Migration Process Overview

*   Download the cord data in JSON format using their REST APls. Send it to us using a secure file-sharing system.
*   We have an internal service written to transform that data and add it to your Velt account. You need not use our APls for this. We will do it for you.
*   It will take about a week for the end-to-end migration process. We can expedite it to be 1-2 days if it's more urgent for you.
*   If you prefer, we can also help you migrate over to Velt on production over a weekend so that your customers don't notice any changes.

## Migration Steps

<Steps titleSize="h2">
  <Step title="Step 1: Provide Test Account Access">
    Give us access to a test account in your app where Cord is implemented. It should contain some cord comments.
  </Step>

  <Step title="Step 2: Export Test Data">
    Export the Cord data from the above test account and send it to us. [Learn more](https://docs.velt.dev/migration/cord-migration/export-cord-data-for-migration)
  </Step>

  <Step title="Step 3: Sample Migration">
    We will migrate that small sample first and verify it with you.
  </Step>

  <Step title="Step 4: Full Data Export">
    Once everything looks good, you will send all of the Cord data as JSON files. We will do a test run on the entire dataset.
  </Step>

  <Step title="Step 5: Schedule Migration">
    Schedule a migration date: On this date, all your cord production data (as of this date) with Velt implemented in your app will go live.
  </Step>
</Steps>


# Overview



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.

### 1. Webhooks

To learn how to trigger email notifications via Webhooks please refer [here](https://docs.velt.dev/webhooks/overview).

### 2. 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

<Warning> The 'From' Email Address needs to be whitelisted from your SendGrid account or else it will not work.</Warning>

## Email Template Data

The following fields are sent to Sendgrid:

| Field             | Type   | Description                                                                                                                                 |
| ----------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| firstComment      | Object | first message in the thread. Contains `commentId`, `commentText` and `from` properties derived from Comment class.                          |
| latestComment     | Object | latest message in the thread that prompted the email. Contains `commentId`, `commentText` and `from` properties derived from Comment class. |
| prevComment       | Object | the previous message to the latestMessage. Contains `commentId`, `commentText` and `from` properties derived from Comment class.            |
| commentsCount     | string | total number of comments in the comment annotation                                                                                          |
| fromUser          | string | action user's object                                                                                                                        |
| commentAnnotation | Object | the comment annotation object without the `comments` field                                                                                  |
| actionType        | Object | the action that resulted in the notification                                                                                                |

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 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 (Right click and view source)][https://firebasestorage.googleapis.com/v0/b/snippyly.appspot.com/o/external%2Femail-template.html?alt=media\&token=16a17614-70ca-464c-b6f4-2b2b097b0007](https://firebasestorage.googleapis.com/v0/b/snippyly.appspot.com/o/external%2Femail-template.html?alt=media\&token=16a17614-70ca-464c-b6f4-2b2b097b0007))

```html
<html lang="en" style="">
<link type="text/css" rel="stylesheet" id="dark-mode-custom-link">
<link type="text/css" rel="stylesheet" id="dark-mode-general-link">
<style lang="en" type="text/css" id="dark-mode-custom-style"></style>
<style lang="en" type="text/css" id="dark-mode-native-style"></style>
<style lang="en" type="text/css" id="dark-mode-native-sheet"></style>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Email Template</title>
</head>

<body style="" data-new-gr-c-s-check-loaded="14.1185.0">
  <div style="margin:0;background-color:#fcfcfd;padding:0">
    <div style="display:none;max-height:0px;overflow:hidden">@here testing here functionality</div>
    <div style="display:none;max-height:0px;overflow:hidden">&nbsp;&nbsp;&nbsp;&nbsp;</div>
    <table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background-color:#fcfcfd">
      <tbody>
        <tr>
          <td>
            <table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation" style="color:#000;width:600px;margin:0 auto"
                      width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1" width="100%"
                            style="font-weight:400;text-align:left;padding-left:15px;padding-right:15px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089image_block m_6043557393601287089block-1" width="100%"
                              border="0" cellpadding="0" cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad"
                                    style="padding-bottom:24px;padding-top:24px;width:100%;padding-right:0;padding-left:0">
                                    <div align="center" style="line-height:10px">
                                      <div style="max-width:142.5px"><svg width="122" height="40" viewBox="0 0 122 40"
                                          fill="none" xmlns="http://www.w3.org/2000/svg">
                                          <rect width="120.125" height="39" transform="translate(0.9375 0.5)"
                                            fill="#FCFCFD"></rect>
                                          <circle cx="16.875" cy="20" r="15.9375" fill="#1E1E1E"></circle>
                                          <path
                                            d="M51.3704 31.5V8.75H55.3354V27.535H64.8092V31.5H51.3704ZM74.1991 31.9225C72.7041 31.9225 71.3391 31.5379 70.1041 30.7687C68.88 29.9996 67.8995 28.9704 67.1629 27.6812C66.437 26.3812 66.0741 24.9458 66.0741 23.375C66.0741 22.1833 66.2854 21.0729 66.7079 20.0437C67.1304 19.0037 67.71 18.0937 68.4466 17.3137C69.1941 16.5229 70.0608 15.9054 71.0466 15.4612C72.0325 15.0171 73.0833 14.795 74.1991 14.795C75.6941 14.795 77.0537 15.1796 78.2779 15.9487C79.5129 16.7179 80.4933 17.7525 81.2191 19.0525C81.9558 20.3525 82.3241 21.7933 82.3241 23.375C82.3241 24.5558 82.1129 25.6608 81.6904 26.69C81.2679 27.7192 80.6829 28.6292 79.9354 29.42C79.1987 30.2 78.3375 30.8121 77.3516 31.2562C76.3766 31.7004 75.3258 31.9225 74.1991 31.9225ZM74.1991 27.9575C74.99 27.9575 75.6995 27.7462 76.3279 27.3238C76.9562 26.9012 77.4491 26.3433 77.8066 25.65C78.175 24.9567 78.3591 24.1983 78.3591 23.375C78.3591 22.53 78.1695 21.7608 77.7904 21.0675C77.422 20.3633 76.9183 19.8054 76.2791 19.3937C75.6508 18.9712 74.9575 18.76 74.1991 18.76C73.4191 18.76 72.715 18.9712 72.0866 19.3937C71.4583 19.8162 70.96 20.3796 70.5916 21.0837C70.2233 21.7879 70.0391 22.5517 70.0391 23.375C70.0391 24.2308 70.2287 25.0054 70.6079 25.6987C70.987 26.3921 71.4908 26.9446 72.1191 27.3562C72.7583 27.7571 73.4516 27.9575 74.1991 27.9575ZM96.9753 15.25H100.94V31.8088C100.94 32.9788 100.702 34.0404 100.225 34.9938C99.7486 35.9579 99.0986 36.7813 98.2753 37.4638C97.4519 38.1571 96.5094 38.6879 95.4478 39.0563C94.3861 39.4354 93.2703 39.625 92.1003 39.625C90.9628 39.625 89.8686 39.3921 88.8178 38.9263C87.7669 38.4604 86.8353 37.8213 86.0228 37.0088C85.2211 36.2071 84.609 35.2917 84.1865 34.2625L87.8103 32.6213C88.0269 33.2171 88.3519 33.7371 88.7853 34.1813C89.2294 34.6363 89.7386 34.9883 90.3128 35.2375C90.8869 35.4975 91.4828 35.6275 92.1003 35.6275C92.7286 35.6275 93.3299 35.5408 93.904 35.3675C94.489 35.1942 95.0144 34.9396 95.4803 34.6038C95.9461 34.2788 96.309 33.8779 96.569 33.4013C96.8399 32.9354 96.9753 32.4046 96.9753 31.8088V29.5175C96.4661 30.2325 95.8269 30.8121 95.0578 31.2562C94.2886 31.7004 93.4003 31.9225 92.3928 31.9225C91.2228 31.9225 90.1286 31.7004 89.1103 31.2562C88.0919 30.8121 87.1928 30.2 86.4128 29.42C85.6436 28.6292 85.0369 27.7192 84.5928 26.69C84.1594 25.6608 83.9428 24.5558 83.9428 23.375C83.9428 22.1942 84.1594 21.0892 84.5928 20.06C85.0369 19.0308 85.6436 18.1262 86.4128 17.3462C87.1928 16.5554 88.0919 15.9379 89.1103 15.4937C90.1286 15.0496 91.2228 14.8275 92.3928 14.8275C93.4003 14.8275 94.2886 15.0496 95.0578 15.4937C95.8269 15.9271 96.4661 16.5012 96.9753 17.2162V15.25ZM92.4415 28.1037C93.2757 28.1037 94.0124 27.8925 94.6515 27.47C95.3015 27.0367 95.8107 26.4625 96.179 25.7475C96.5474 25.0217 96.7315 24.2308 96.7315 23.375C96.7315 22.5083 96.5419 21.7175 96.1628 21.0025C95.7944 20.2875 95.2853 19.7133 94.6353 19.28C93.9961 18.8467 93.2649 18.63 92.4415 18.63C91.629 18.63 90.8869 18.8467 90.2153 19.28C89.5436 19.7025 89.0074 20.2712 88.6065 20.9862C88.2057 21.7012 88.0053 22.4975 88.0053 23.375C88.0053 24.2525 88.2057 25.0487 88.6065 25.7637C89.0074 26.4787 89.5436 27.0475 90.2153 27.47C90.8869 27.8925 91.629 28.1037 92.4415 28.1037ZM111.619 31.9225C110.124 31.9225 108.759 31.5379 107.524 30.7687C106.299 29.9996 105.319 28.9704 104.582 27.6812C103.856 26.3812 103.494 24.9458 103.494 23.375C103.494 22.1833 103.705 21.0729 104.127 20.0437C104.55 19.0037 105.129 18.0937 105.866 17.3137C106.614 16.5229 107.48 15.9054 108.466 15.4612C109.452 15.0171 110.503 14.795 111.619 14.795C113.114 14.795 114.473 15.1796 115.697 15.9487C116.932 16.7179 117.913 17.7525 118.639 19.0525C119.375 20.3525 119.744 21.7933 119.744 23.375C119.744 24.5558 119.532 25.6608 119.11 26.69C118.687 27.7192 118.102 28.6292 117.355 29.42C116.618 30.2 115.757 30.8121 114.771 31.2562C113.796 31.7004 112.745 31.9225 111.619 31.9225ZM111.619 27.9575C112.409 27.9575 113.119 27.7462 113.747 27.3238C114.376 26.9012 114.869 26.3433 115.226 25.65C115.594 24.9567 115.779 24.1983 115.779 23.375C115.779 22.53 115.589 21.7608 115.21 21.0675C114.841 20.3633 114.338 19.8054 113.699 19.3937C113.07 18.9712 112.377 18.76 111.619 18.76C110.839 18.76 110.134 18.9712 109.506 19.3937C108.878 19.8162 108.379 20.3796 108.011 21.0837C107.643 21.7879 107.459 22.5517 107.459 23.375C107.459 24.2308 107.648 25.0054 108.027 25.6987C108.406 26.3921 108.91 26.9446 109.539 27.3562C110.178 27.7571 110.871 27.9575 111.619 27.9575Z"
                                            fill="#1E1E1E"></path>
                                        </svg>


                                      </div>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                            <table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div align="center">
                                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
                                        width="100%">
                                        <tbody>
                                          <tr>
                                            <td style="font-size:1px;line-height:1px;border-top:1px solid #d9d9d9">
                                              <span> </span>
                                            </td>
                                          </tr>
                                        </tbody>
                                      </table>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="border-radius:0;color:#000;width:600px;margin:0 auto" width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1" width="100%"
                            style="font-weight:400;text-align:left;padding-bottom:20px;padding-top:20px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
              style="background-color:#fcfcfd">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="border-radius:0;color:#000;width:600px;margin:0 auto" width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1"
                            width="33.333333333333336%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column m_6043557393601287089column-2"
                            width="33.333333333333336%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div style="font-family:Arial,Helvetica Neue,Helvetica,sans-serif;text-align:center"
                                      align="center">
                                      <img src="{{photoUrl}}"
                                        style="width:120px;height:120px;object-fit:cover;border-radius:60px"
                                        class="CToWUd" data-bit="iit">
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column" width="33.333333333333336%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="border-radius:0;color:#000;width:600px;margin:0 auto" width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1"
                            width="16.666666666666668%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column m_6043557393601287089column-2"
                            width="66.66666666666667%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089heading_block m_6043557393601287089block-1" width="100%"
                              border="0" cellpadding="0" cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad"
                                    style="padding-top:12px;text-align:center;width:100%">
                                    <h1
                                      style="margin:0;color:#141416;direction:ltr;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:28px;font-weight:700;letter-spacing:normal;line-height:120%;text-align:center;margin-top:0;margin-bottom:0">
                                      <span>{{messageFromName}} mentioned you on <span
                                          style="color:#625df5">{{pageTitle}}</span></span>
                                    </h1>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column" width="16.666666666666668%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation"
              style="background-color:#fcfcfd">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="background-color:#fcfcfd;border-radius:0;color:#000;width:600px;margin:0 auto" width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1" width="100%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation" style="word-break:break-word">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad"
                                    style="padding-bottom:10px;padding-left:10px;padding-right:10px;padding-top:5px">
                                    <div
                                      style="color:#777e90;direction:ltr;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:16px;font-weight:400;letter-spacing:0;line-height:150%;text-align:center">
                                      <p style="margin:0"><a href="{{pageUrl}}"
                                          style="text-decoration:underline;color:#777e90" rel="noopener"
                                          target="_blank">{{pageUrl}}</a>
                                      </p>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="border-radius:0;color:#000;width:600px;margin:0 auto" width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1" width="100%"
                            style="font-weight:400;text-align:left;padding-bottom:12px;padding-left:12px;padding-right:12px;padding-top:12px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table class="m_6043557393601287089row-8" align="center" width="100%" border="0" cellpadding="0"
              cellspacing="0" role="presentation" style="background-color:#fcfcfd">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content" align="center" border="0" cellpadding="0"
                      cellspacing="0" role="presentation"
                      style="background-color:#fff;border-bottom:1px solid #e6e8ec;border-left:1px solid #e6e8ec;border-radius:20px;border-right:1px solid #e6e8ec;border-top:1px solid #e6e8ec;color:#000;width:600px;margin:0 auto"
                      width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1"
                            width="16.666666666666668%"
                            style="font-weight:400;text-align:left;padding-left:24px;vertical-align:middle;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column m_6043557393601287089column-2"
                            width="66.66666666666667%"
                            style="font-weight:400;text-align:left;padding-bottom:24px;padding-top:24px;vertical-align:middle;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089heading_block m_6043557393601287089block-1" width="100%"
                              border="0" cellpadding="0" cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad" style="text-align:center;width:100%">
                                    <h2
                                      style="margin:0;color:#23262f;direction:ltr;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:18px;font-weight:400;letter-spacing:normal;line-height:180%;text-align:center;margin-top:0;margin-bottom:0">
                                      <span>{{message}}</span>
                                    </h2>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column" width="16.666666666666668%"
                            style="font-weight:400;text-align:left;padding-right:24px;vertical-align:middle;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table align="center" width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="border-radius:0;color:#000;width:600px;margin:0 auto" width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1"
                            width="33.333333333333336%"
                            style="font-weight:400;text-align:left;vertical-align:middle;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div style="font-family:Arial,Helvetica Neue,Helvetica,sans-serif;text-align:center"
                                      align="center"><img width="20px" align="right"
                                        src="https://ci3.googleusercontent.com/meips/ADKq_Na5Ar6lpj8J11QBnXruiVXOyHIrHcvB96ZKd3ArstcM-s6ykE728bQGkZhA7AiE3rUGviILT9XvMOUCFNyk3zHdfdcen07yk1cPKt6QM6tFGsf2xPE5-tVjw7yxxjGpa040LhIFdkfmQLDOaLp40tNKxfC_O3sFf2IWXOgejd5FxUkPMjhpSeqbsUfQbA=s0-d-e1-ft#https://userimg-assets.customeriomail.com/images/client-env-130244/1708534324378_Devices_01HQ699Q8RBX2NETB0H7ECFBQC.png"
                                        class="CToWUd" data-bit="iit"></div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column m_6043557393601287089column-2" width="50%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:middle;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation" style="word-break:break-word">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad"
                                    style="padding-bottom:20px;padding-left:10px;padding-right:10px;padding-top:20px">
                                    <div
                                      style="color:#515151;direction:ltr;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:14px;font-weight:400;letter-spacing:0;line-height:120%;text-align:left">
                                      <p style="margin:0"><span style="color:#000101">{{deviceInfo.deviceType}} •
                                          {{deviceInfo.screenWidth}}
                                          x {{deviceInfo.screenHeight}}</span>&nbsp;<span
                                          style="color:#8b8b8b">{{deviceInfo.browserName}}</span></p>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                          <td class="m_6043557393601287089column" width="16.666666666666668%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:middle;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="10"
                              cellspacing="0" role="presentation" style="word-break:break-word">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div
                                      style="color:#838383;direction:ltr;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:14px;font-weight:400;letter-spacing:0;line-height:120%;text-align:left">
                                      &nbsp;</div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table class="m_6043557393601287089row-10" align="center" width="100%" border="0" cellpadding="0"
              cellspacing="0" role="presentation" style="background-color:#fcfcfd">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="background-color:#fcfcfd;border-left:0 solid #e6e8ec;border-radius:0;border-right:0 solid #e6e8ec;color:#000;width:600px;margin:0 auto"
                      width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1" width="100%"
                            style="font-weight:400;text-align:left;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089button_block m_6043557393601287089block-1" width="100%"
                              border="0" cellpadding="0" cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad"
                                    style="padding-bottom:35px;padding-left:10px;padding-right:10px;padding-top:12px;text-align:center">
                                    <div align="center"><a href="{{pageUrl}}"
                                        style="text-decoration:none;display:inline-block;color:#fff;background-color:#625df5;border-radius:50px;width:auto;border-top:0 solid transparent;font-weight:700;border-right:0 solid transparent;border-bottom:0 solid transparent;border-left:0 solid transparent;padding-top:16px;padding-bottom:16px;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:16px;text-align:center;word-break:keep-all"
                                        target="_blank"><span
                                          style="padding-left:24px;padding-right:24px;font-size:16px;display:inline-block;letter-spacing:normal"><span
                                            style="word-break:break-word;line-height:24px">View
                                            the <span class="il">comment</span></span></span></a>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table class="m_6043557393601287089row-11" align="center" width="100%" border="0" cellpadding="0"
              cellspacing="0" role="presentation">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="border-left:0 solid #e6e8ec;border-radius:0;border-right:0 solid #e6e8ec;color:#000;width:600px;margin:0 auto"
                      width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1" width="100%"
                            style="font-weight:400;text-align:left;padding-bottom:35px;padding-left:15px;padding-right:15px;padding-top:60px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089block-1" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad">
                                    <div align="center">
                                      <table border="0" cellpadding="0" cellspacing="0" role="presentation"
                                        width="100%">
                                        <tbody>
                                          <tr>
                                            <td style="font-size:1px;line-height:1px;border-top:1px solid #d9d9d9">
                                              <span> </span>
                                            </td>
                                          </tr>
                                        </tbody>
                                      </table>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
            <table class="m_6043557393601287089row-12" align="center" width="100%" border="0" cellpadding="0"
              cellspacing="0" role="presentation">
              <tbody>
                <tr>
                  <td>
                    <table class="m_6043557393601287089row-content m_6043557393601287089stack" align="center" border="0"
                      cellpadding="0" cellspacing="0" role="presentation"
                      style="border-radius:0;color:#000;width:600px;margin:0 auto" width="600">
                      <tbody>
                        <tr>
                          <td class="m_6043557393601287089column m_6043557393601287089column-1" width="100%"
                            style="font-weight:400;text-align:left;padding-bottom:5px;padding-top:5px;vertical-align:top;border-top:0;border-right:0;border-bottom:0;border-left:0">
                            <table class="m_6043557393601287089image_block m_6043557393601287089block-1" width="100%"
                              border="0" cellpadding="0" cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad"
                                    style="width:100%;padding-right:0;padding-left:0">
                                    <div align="center" style="line-height:10px">
                                      <div style="max-width:138px"><svg width="122" height="40" viewBox="0 0 122 40"
                                          fill="none" xmlns="http://www.w3.org/2000/svg">
                                          <rect width="120.125" height="39" transform="translate(0.9375 0.5)"
                                            fill="#FCFCFD"></rect>
                                          <circle cx="16.875" cy="20" r="15.9375" fill="#1E1E1E"></circle>
                                          <path
                                            d="M51.3704 31.5V8.75H55.3354V27.535H64.8092V31.5H51.3704ZM74.1991 31.9225C72.7041 31.9225 71.3391 31.5379 70.1041 30.7687C68.88 29.9996 67.8995 28.9704 67.1629 27.6812C66.437 26.3812 66.0741 24.9458 66.0741 23.375C66.0741 22.1833 66.2854 21.0729 66.7079 20.0437C67.1304 19.0037 67.71 18.0937 68.4466 17.3137C69.1941 16.5229 70.0608 15.9054 71.0466 15.4612C72.0325 15.0171 73.0833 14.795 74.1991 14.795C75.6941 14.795 77.0537 15.1796 78.2779 15.9487C79.5129 16.7179 80.4933 17.7525 81.2191 19.0525C81.9558 20.3525 82.3241 21.7933 82.3241 23.375C82.3241 24.5558 82.1129 25.6608 81.6904 26.69C81.2679 27.7192 80.6829 28.6292 79.9354 29.42C79.1987 30.2 78.3375 30.8121 77.3516 31.2562C76.3766 31.7004 75.3258 31.9225 74.1991 31.9225ZM74.1991 27.9575C74.99 27.9575 75.6995 27.7462 76.3279 27.3238C76.9562 26.9012 77.4491 26.3433 77.8066 25.65C78.175 24.9567 78.3591 24.1983 78.3591 23.375C78.3591 22.53 78.1695 21.7608 77.7904 21.0675C77.422 20.3633 76.9183 19.8054 76.2791 19.3937C75.6508 18.9712 74.9575 18.76 74.1991 18.76C73.4191 18.76 72.715 18.9712 72.0866 19.3937C71.4583 19.8162 70.96 20.3796 70.5916 21.0837C70.2233 21.7879 70.0391 22.5517 70.0391 23.375C70.0391 24.2308 70.2287 25.0054 70.6079 25.6987C70.987 26.3921 71.4908 26.9446 72.1191 27.3562C72.7583 27.7571 73.4516 27.9575 74.1991 27.9575ZM96.9753 15.25H100.94V31.8088C100.94 32.9788 100.702 34.0404 100.225 34.9938C99.7486 35.9579 99.0986 36.7813 98.2753 37.4638C97.4519 38.1571 96.5094 38.6879 95.4478 39.0563C94.3861 39.4354 93.2703 39.625 92.1003 39.625C90.9628 39.625 89.8686 39.3921 88.8178 38.9263C87.7669 38.4604 86.8353 37.8213 86.0228 37.0088C85.2211 36.2071 84.609 35.2917 84.1865 34.2625L87.8103 32.6213C88.0269 33.2171 88.3519 33.7371 88.7853 34.1813C89.2294 34.6363 89.7386 34.9883 90.3128 35.2375C90.8869 35.4975 91.4828 35.6275 92.1003 35.6275C92.7286 35.6275 93.3299 35.5408 93.904 35.3675C94.489 35.1942 95.0144 34.9396 95.4803 34.6038C95.9461 34.2788 96.309 33.8779 96.569 33.4013C96.8399 32.9354 96.9753 32.4046 96.9753 31.8088V29.5175C96.4661 30.2325 95.8269 30.8121 95.0578 31.2562C94.2886 31.7004 93.4003 31.9225 92.3928 31.9225C91.2228 31.9225 90.1286 31.7004 89.1103 31.2562C88.0919 30.8121 87.1928 30.2 86.4128 29.42C85.6436 28.6292 85.0369 27.7192 84.5928 26.69C84.1594 25.6608 83.9428 24.5558 83.9428 23.375C83.9428 22.1942 84.1594 21.0892 84.5928 20.06C85.0369 19.0308 85.6436 18.1262 86.4128 17.3462C87.1928 16.5554 88.0919 15.9379 89.1103 15.4937C90.1286 15.0496 91.2228 14.8275 92.3928 14.8275C93.4003 14.8275 94.2886 15.0496 95.0578 15.4937C95.8269 15.9271 96.4661 16.5012 96.9753 17.2162V15.25ZM92.4415 28.1037C93.2757 28.1037 94.0124 27.8925 94.6515 27.47C95.3015 27.0367 95.8107 26.4625 96.179 25.7475C96.5474 25.0217 96.7315 24.2308 96.7315 23.375C96.7315 22.5083 96.5419 21.7175 96.1628 21.0025C95.7944 20.2875 95.2853 19.7133 94.6353 19.28C93.9961 18.8467 93.2649 18.63 92.4415 18.63C91.629 18.63 90.8869 18.8467 90.2153 19.28C89.5436 19.7025 89.0074 20.2712 88.6065 20.9862C88.2057 21.7012 88.0053 22.4975 88.0053 23.375C88.0053 24.2525 88.2057 25.0487 88.6065 25.7637C89.0074 26.4787 89.5436 27.0475 90.2153 27.47C90.8869 27.8925 91.629 28.1037 92.4415 28.1037ZM111.619 31.9225C110.124 31.9225 108.759 31.5379 107.524 30.7687C106.299 29.9996 105.319 28.9704 104.582 27.6812C103.856 26.3812 103.494 24.9458 103.494 23.375C103.494 22.1833 103.705 21.0729 104.127 20.0437C104.55 19.0037 105.129 18.0937 105.866 17.3137C106.614 16.5229 107.48 15.9054 108.466 15.4612C109.452 15.0171 110.503 14.795 111.619 14.795C113.114 14.795 114.473 15.1796 115.697 15.9487C116.932 16.7179 117.913 17.7525 118.639 19.0525C119.375 20.3525 119.744 21.7933 119.744 23.375C119.744 24.5558 119.532 25.6608 119.11 26.69C118.687 27.7192 118.102 28.6292 117.355 29.42C116.618 30.2 115.757 30.8121 114.771 31.2562C113.796 31.7004 112.745 31.9225 111.619 31.9225ZM111.619 27.9575C112.409 27.9575 113.119 27.7462 113.747 27.3238C114.376 26.9012 114.869 26.3433 115.226 25.65C115.594 24.9567 115.779 24.1983 115.779 23.375C115.779 22.53 115.589 21.7608 115.21 21.0675C114.841 20.3633 114.338 19.8054 113.699 19.3937C113.07 18.9712 112.377 18.76 111.619 18.76C110.839 18.76 110.134 18.9712 109.506 19.3937C108.878 19.8162 108.379 20.3796 108.011 21.0837C107.643 21.7879 107.459 22.5517 107.459 23.375C107.459 24.2308 107.648 25.0054 108.027 25.6987C108.406 26.3921 108.91 26.9446 109.539 27.3562C110.178 27.7571 110.871 27.9575 111.619 27.9575Z"
                                            fill="#1E1E1E"></path>
                                        </svg>
                                      </div>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                            <table class="m_6043557393601287089heading_block" width="100%" border="0" cellpadding="0"
                              cellspacing="0" role="presentation">
                              <tbody>
                                <tr>
                                  <td class="m_6043557393601287089pad"
                                    style="padding-bottom:20px;padding-top:30px;text-align:center;width:100%">
                                    <h1
                                      style="margin:0;color:#94959a;direction:ltr;font-family:Arial,Helvetica Neue,Helvetica,sans-serif;font-size:14px;font-weight:400;letter-spacing:normal;line-height:120%;text-align:center;margin-top:0;margin-bottom:0">
                                      <span>© 2022 Copyright by
                                        App</span>
                                    </h1>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </td>
                </tr>
              </tbody>
            </table>
          </td>
        </tr>
      </tbody>
    </table><img
      src="https://ci3.googleusercontent.com/meips/ADKq_NYM51xIFNwXihKgeLlqyVP97ulnam3VRxruLR0Ara84A14_WErGd9ykG7JDdnAgugP8jqQEweCGvvMIpGvGEawL0d4GJ7YUsmQuJQ0YB4vJk5Bl2toU80GONxy-HGPQvUnOX_kaLV-9X05YoL6VMwePfm6IFGcnTQ=s0-d-e1-ft#http://email.usesuperflow.com/e/o/eyJlbWFpbF9pZCI6IlJNVDVCd1VBQVk4enNRWGk4LXVFRHVCOWdXdG9mQT09In0="
      style="height:1px!important;max-height:1px!important;max-width:1px!important;width:1px!important;display:none!important"
      alt="" class="CToWUd" data-bit="iit" jslog="138226; u014N:xr6bB; 53:WzAsMl0.">

    <img
      src="https://ci3.googleusercontent.com/meips/ADKq_NbgCaKQqeUeI8KB87L2bph8vRubUY2YNAke4I50mlNuZUz1H6ou__qBq0qRUQLwsSTOfEWMoXzKFcYDVLE3lOR8Wai2u5RQ7jPYpKTxnes1mfcPaWOxI7X3KvUS15N0UDtv8TBj9SM1Nf3uKdvduN4PZMu_qotMqMwvpUoVoS_KODRaQ1RjvbYHYrjLoW1nGU_RJcQrCHMcL_hAEfl3xFoXmWWtFH346jT6gJCplDpnJV6gnGPPhE-LvTUMWYCw16Sg00L_4QnhbBwP9GwaQzL9arU0dcjJRA40XAEevlTNVyBiVnAn06Ur9KBNXJlOunu01iwggTUy5WoouYzUhnrKaeEcL9AQISFgcG-T5YMkgqYSm3tr14pIsT8-CBOwIka9Suq1v874DfbJ4euHqdzY7PdH3SaDJDw8-qxG6naEgnhgpOpo1BPhQHXZTTzUIRdE6_jxjFAZfMUdv-AxGeRAtXNg56dqV8Vukz-7rN8dIRo9ljmyPvQYsotPCG6AG9yN8Rg=s0-d-e1-ft#http://url3921.usesuperflow.com/wf/open?upn=u001.Dc4eXJJC3dnABjL2PM3i-2BxAbjHZZmw-2FIX9dDzjMpNLfr94HZvqwfrTJfOIes5K6ZAOurKf1fJN30gg6rr9Vu-2Bw3YqgdsWUYdhTyfETJ5HllIOeIqyl1ZAYmaWazHIwK0FMF7ujoQDxwnooMMBUdRIes68yAT4jzh-2BemnBuqBU7b2F6Eu1oof-2Flow7-2BhB7UnM6ciOJQbkmwUWeLzFCH2r0uUQiZDrLC4uWmqslfC1hFxKufd3V7e48vdI9q-2BgES1GFyHlU7DPs2nA4P31FehS0AFYN7MeMA4gYuUM7bvzq1M-3D"
      alt="" width="1" height="1" border="0"
      style="height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important"
      class="CToWUd" data-bit="iit" jslog="138226; u014N:xr6bB; 53:WzAsMl0.">
  </div>






</body>

</html>
```


# Customize Behavior



<Tabs>
  <Tab title="React">
    ## 1. Enable avatar mode

    Show the user's avatar floating next to their cursor instead of their name.

    Enabling this mode will allow you to show the user's avatar in context with the cursor.

    ```js
    <VeltCursor avatarMode={true} />
    ```

    ## 2. Set inactivity time

    Set the time it takes for a user to go inactive in milliseconds.

    By default we mark a user as inactive if they do not take any action on the document within a 5 mins timeframe.

    If they unfocus the tab, we mark them inactive immediately.

    ```js
    <VeltCursor inactivityTime={300000} />
    ```

    ## 3. Set allowed element IDs

    Provide a list of element IDs where the cursors should show.

    If you provide a list of element IDs, we will only show cursors that hover over those specific elements.

    For eg: For an app with canvas and tool picker: You can whitelist the canvas ID so that the cursors are only visible on the canvas and not the tool picker.

    ```js
    <VeltCursor allowedElementIds={JSON.stringify(['element-1', 'element-2'])} />
    ```

    <Warning>You must pass a string into allowedElementIds instead of an object</Warning>

    ## 4. Subscribe to changes in User Cursors

    Whenever the cursor for any user changes, we emit this event with the updated list of users currently online on this document with their cursor positions.

    ```js
    <VeltCursor onCursorUserChange={(cursorUsers) => yourMethod(cursorUsers)} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ## 1. Enable avatar mode

    Show the user's avatar floating next to their cursor.

    Enabling this mode will allow you to show the user's avatar in context with the cursor.

    ```html
    <velt-cursor avatar-mode="true"></velt-cursor>
    ```

    ## 2. Set inactivity time

    Set the time it takes for a cursor to disappear.
    If a user leaves their mouse cursor, set the time it takes for that cursor to disappear on everyone else's screen. If they unfocus the tab, they will immediately go inactive

    ```html
    <velt-cursor inactivity-time="300000"></velt-cursor>
    ```

    ## 3. Set allowed element IDs

    Whitelist allowed elements
    If you provide a list of element IDs, we will only show cursors that hover over those specific elements.

    ```html
    <velt-cursor allowed-element-ids='["element-1", "element-2"]'></velt-cursor>
    ```

    ## 4. Subscribe to changes in User Cursors

    Whenever the cursor for any user changes, we emit this event with the updated list of users currently online on this document with their cursor positions.

    ```js
    <script>
    if(Velt){
      const cursorElement = Velt.getCursorElement();

      cursorlement.addEventListener('onCursorUserChange', (event) => {
        console.log("onCursorUserChange", event.detail);
      });
    }
    </script>
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```js React
  import { VeltProvider, VeltCursor } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">
        <VeltCursor
          avatarMode={true} {/* 1) Enable avatar mode */}
          inactivityTime={300000} {/* 2) Set inactivity time */}
          allowedElementIds={JSON.stringify(['element-1', 'element-2'])} {/* 3) Set allowed element IDs */}
          onCursorUserChange={(cursorUsers) => yourMethod(cursorUsers)} {/* 4) Subscribe to changes in User Cursors */}
        />
      </VeltProvider>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Cursors documentation</title>
      <script>
        if(Velt){
          const cursorElement = Velt.getCursorElement();
          cursorlement.addEventListener('onCursorUserChange', (event) => {
            console.log("onCursorUserChange", event.detail);
          });
        }
      </script>
    </head>
    <body>
      <velt-cursor
        avatar-mode="true" <!-- 1) Enable avatar mode -->
        inactivity-time="300000" <!-- 2) Set inactivity time -->
        allowed-element-ids='["element-1", "element-2"]' <!-- 3) Set allowed element IDs -->
      ></velt-cursor>
    </body>
  </html>
  ```
</RequestExample>


# Overview

Your users can view each other's cursors when interacting on the same document. This makes your app more alive. We handle the complexity of adapting the cursors to different screen sizes, differences in content etc.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=cursors" scrolling="no" frameBorder="0" className="w-full" height="500px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=cursors)


# null



<Tabs>
  <Tab title="React / Next.js">
    <Steps>
      <Step title="Import the VeltCursor Component">
        Import the `VeltCursor` component.

        ```js
        import { VeltProvider, VeltCursor } from '@veltdev/react'
        ```
      </Step>

      <Step title="Add the VeltCursor Component">
        Add the `VeltCursor` component to the root of your app.

        ```js
        <VeltProvider apiKey="API_KEY">
              <VeltCursor />
              {/* ... */}
        </VeltProvider>
        ```

        This component renders the cursors of users on the same document and location in your web app.

        <Info>
          Note that we automatically assign different colors to users & adapt the cursors to different screen sizes and to what's actually present on the screen. So you don't have to worry about building this logic.
        </Info>
      </Step>

      <Step title="Test Integration">
        Test it out by opening the target page in two browsers (with one in incognito) with two different users logged in.

        You should see the cursors of the users rendered as you move mouse around.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps>
      <Step title="Place the <velt-cursor> component">
        Add the `<velt-cursor>` component to the root of your app.

        ```html
        <body>
          <velt-cursor></velt-cursor>
        </body>
        ```

        This component renders the cursors of users on the same document and location in your web app.

        <Info>
          Note that we automatically assign different colors to users & adapt the cursors to different screen sizes and to what's actually present on the screen. So you don't have to worry about building this logic.
        </Info>
      </Step>

      <Step title="Test Integration">
        Test it out by opening the target page in two browsers (with one in incognito) with two different users logged in.

        You should see the cursors of the users rendered as you move mouse around.
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { VeltProvider, VeltCursor } from '@veltdev/react';

  export default function App() {

    return (
      <VeltProvider apiKey="API_KEY">
        <VeltCursor />
        {/* ... */}
      </VeltProvider>
    );
  }
  ```

  ```js HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Cursors documentation</title>
    </head>
    <body>
      <velt-cursor></velt-cursor>
    </body>
  </html>

  ```
</RequestExample>


# Customize Behavior



<Tabs>
  <Tab title="React / Next.js">
    ## 1. Enable custom navigation

    Use a callback for custom navigation or side-effects.

    When the leader of a `Follow Me` session navigates, we can use the React Router to update the follower's position. In the callback you will receive a `PageInfo` object.

    ```js
    <VeltPresence onNavigate={(pageInfo) => navigate(pageInfo.path)} />
    ```

    ### PageInfo

    | property  | type   | description                 |
    | --------- | ------ | --------------------------- |
    | `baseUrl` | string | The base URL of the site    |
    | `path`    | string | The path after the base URL |
    | `url`     | string | The full URL                |

    ## 2. Disable default Follow Me navigation

    Disable default `Follow Me` navigation.

    `Default: true`

    Our default navigation uses window\.location.href to detect navigation. If you are handling navigation using the callback method above, you should disable our default navigation.

    ```js
    <VeltPresence defaultFlockNavigation={true} />
    ```

    ## 3. Start or Stop Following a User

    You can start or Stop Following a User by calling the `startFollowingUser()` and `stopFollowingUser()` methods within a useEffect() hook.

    ### Start Following

    Start following a user by passing in their user ID to the `startFollowingUser()` method.

    You can programatically start a `Follow Me` session by passing in the user ID of the user you want to lead the session.

    ```js
    // Start following the user
    presenceElement.startFollowingUser(userId);
    ```

    ### Stop Following

    Stop `Follow Me` session for the current user by by calling the `stopFollowingUser()` method.

    If the current user is in a `Follow Me` session, they will be removed from that session. If there are no more followers in the session, the session will be destroyed.

    ```js
    // Stop following the user
    presenceElement.stopFollowingUser();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ## 1. Enable custom navigation

    Use a callback for custom navigation or side-effects.

    When the leader of a `Follow Me` session navigates, we can use the React Router to update the follower's position. In the callback you will receive a `PageInfo` object.

    ```js

    let onNavigateHandler = (pageInfo) => navigate(pageInfo.path);

    if (presenceDOMElement) {
      presenceDOMElement.addEventListener("onNavigate", onNavigateHandler);
    }
    ```

    ### PageInfo

    | property  | type   | description                 |
    | --------- | ------ | --------------------------- |
    | `baseUrl` | string | The base URL of the site    |
    | `path`    | string | The path after the base URL |
    | `url`     | string | The full URL                |

    ## 2. Disable default Follow Me navigation

    Disable default `Follow Me` navigation.

    `Default: true`

    If you are handling navigation using a callback, you can opt to disable our default navigation using window\.location.href.

    ```js
    <velt-presence disable-flock-navigation="true"></velt-presence>
    ```

    ## 3. Start or Stop Following a User

    You can start or Stop Following a User by calling the `startFollowingUser()` and `stopFollowingUser()` methods within a script tag.

    ### Start Following

    Start following a user by passing in their user ID to the `startFollowingUser()` method.

    You can programatically start a `Follow Me` session by passing in the user ID of the user you want to lead the session.

    ```js
    // Start following the user
    presenceElement.startFollowingUser(userId);
    ```

    ### Stop Following

    Stop `Follow Me` session for the current user by by calling the `stopFollowingUser()` method.

    If the current user is in a `Follow Me` session, they will be removed from that session. If there are no more followers in the session, the session will be destroyed.

    ```js
    // Stop following the user
    presenceElement.stopFollowingUser();
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```js React
  import { VeltPresence } from '@veltdev/react';
  import { useNavigate } from 'react-router-dom';
  import { useEffect } from 'react';

  export default function App() {

    useEffect(() => {
      if (client) {

        const presenceElement = client.getPresenceElement();

        // Pass in the user ID of the user you want to follow
        presenceElement.startFollowingUser(userId);

        // Stop following the user
        presenceElement.stopFollowingUser();

      }
    }, [client]);

    const navigate = useNavigate();

    return (
      <div className="toolbar">
        <VeltPresence
          flockMode={true} 
          onNavigate={(pageInfo) => navigate(pageInfo.path)} {/* 1) Enable Custom Navigation */}
          defaultFlockNavigation={true} {/* 2) Disable Default Follow Me Navigation */}
        />
      </div>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Follow Me mode documentation</title>
    </head>
    <body>
      <script>
        function onNavigateHandler(pageInfo) {
          // Do something with pageInfo
        }

        const presenceDOMElement = document.querySelector("velt-presence");

        //Enable Custom Navigation
        if (presenceDOMElement) {
          presenceDOMElement.addEventListener("onNavigate", onNavigateHandler);
        }

        if (window.Velt) {
          const presenceElement = window.Velt.getPresenceElement();

          // Pass in the user ID of the user you want to follow
          presenceElement.startFollowingUser(userId);

          // Stop following the user
          presenceElement.stopFollowingUser();
        }
      </script>

      <div class="toolbar">
        <velt-presence
          flock-mode="true"
          default-flock-navigation="true"
        ></velt-presence>
      </div>
    </body>
  </html>
  ```
</RequestExample>


# Overview

This is like Figma's follow along feature. Start a shared session in a click. One person is the leader, and whatever they do - like clicking, scrolling, or navigating - happens automatically on everyone else's screen.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=flock" scrolling="no" frameBorder="0" className="w-full" height="500px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=flock)


# Setup



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Enable Follow Me mode on Presence">
        Enable `Follow Me` mode feature.

        ```js
         <VeltPresence flockMode={true} />
        ```

        You need to add the [Presence feature](/realtime-collaboration/presence/overview) to trigger `Follow Me` mode. This will enable `Follow Me` mode as an option for your users globally, wherever `Presence` is shown.

        To start the shared `Follow Me` session, click on a user's avatar to start following them.
      </Step>

      <Step title="Test Integration">
        Test it out by opening the target page in two browsers with two different users logged in.

        You should see the avatars of the users rendered where you added the `Presence` component. Now click on any avatar to start following them.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Enable Follow Me mode on Presence">
        Enable `Follow Me` mode feature.

        ```html
        <velt-presence flock-mode="true"></velt-presence>
        ```

        You need to add [Presence feature](/realtime-collaboration/presence/overview) to trigger `Follow Me` mode. This will enable `Follow Me` mode as an option for your users globally, wherever Presence is shown.

        To start the shared `Follow Me` session, click on a user's avatar to start following them.
      </Step>

      <Step title="Test Integration">
        Test it out by opening the target page in two browsers with two different users logged in.

        You should see the avatars of the users rendered where you added the presence component. Now click on any avatar to start following them.
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { VeltPresence } from '@veltdev/react';

  export default function App() {

    return (
      <div className="toolbar">
        <VeltPresence
          flockMode={true} {/* 1) Enable Follow Me Mode */}
        />
      </div>
    );
  }
  ```

  ```html HTML
  <velt-presence flock-mode="true"></velt-presence> <!-- Enable Follow Me Mode -->
  ```
</RequestExample>


# Customize Behavior



<Tabs>
  <Tab title="React / Next.js">
    ## 1. Enable Audio Only Mode

    Sets the mode to audio only mode.

    This is the default mode if no type is provided.

    ```jsx
    <VeltHuddleTool type="audio"/>
    ```

    ## 2. Enable Video Only Mode

    Sets the mode to video only mode.

    ```jsx
    <VeltHuddleTool type="video"/>
    ```

    ## 3. Enable Screen Only Mode

    Sets the mode to screen only mode.

    ```jsx
    <VeltHuddleTool type="screen"/>
    ```

    ## 4. Enable All Modes

    Sets the mode to all modes.

    ```jsx
    <VeltHuddleTool type="all"/>
    ```

    ## 5. Dark Mode

    Whether dark mode is enabled.

    `Default: false`

    ```js
    <VeltHuddle darkMode={true} />
    ```

    ## 6. Disable Chat Feature

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/chat-in-huddle.png)

    Whether Chat feature is disabled in `Huddles`.

    `Default: true`

    ```js
    <VeltHuddle chat={false} />
    ```

    API Methods:

    ```jsx
    const huddleElement = client.getHuddleElement();
    // to enable chat
    huddleElement.enableChat();
    // to disable chat
    huddleElement.disableChat();
    ```

    ## 7. Enable Flock Mode on Avatar Click

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/huddle-flock.gif)

    Whether Flock Mode on Avatar Click is enabled in `Huddles`.

    `Default: false`

    ```js
    <VeltHuddle flockModeOnAvatarClick={true} />
    ```

    API Methods:

    ```jsx
    const huddleElement = client.getHuddleElement();
    // to enable flock mode on avatar click
    huddleElement.enableFlockModeOnAvatarClick();
    // to disable flock mode on avatar click
    huddleElement.disableFlockModeOnAvatarClick();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ## 1. Enable Audio Only Mode

    Sets the mode to audio only mode.

    This is the default mode if no type is provided.

    ```jsx
    <velt-huddle-tool type="audio"></velt-huddle-tool>
    ```

    ## 2. Enable Video Only Mode

    Sets the mode to video only mode.

    ```jsx
    <velt-huddle-tool  type="video"></velt-huddle-tool>
    ```

    ## 3. Enable Screen Only Mode

    Sets the mode to screen only mode.

    ```jsx
    <velt-huddle-tool type="screen"></velt-huddle-tool>
    ```

    ## 4. Enable All Modes

    Sets the mode to all modes.

    ```jsx
    <velt-huddle-tool  type="all"></velt-huddle-tool>
    ```

    ## 5. Dark Mode

    Whether dark mode is enabled.

    `Default: false`

    ```js
    <velt-huddle dark-mode="true"></velt-huddle>
    ```

    ## 6. Disable Chat Feature

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/chat-in-huddle.png)

    Whether Chat feature is disabled in `Huddles`.

    `Default: true`

    ```js
    <velt-huddle chat="false" flock-mode-on-avatar-click="true"></velt-huddle>
    ```

    API Methods:

    ```jsx
    const huddleElement = client.getHuddleElement();
    // to enable chat
    huddleElement.enableChat();
    // to disable chat
    huddleElement.disableChat();
    ```

    ## 7. Enable Flock Mode on Avatar Click

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/huddle-flock.gif)

    Whether Flock Mode on Avatar Click is enabled in `Huddles`.

    `Default: false`

    ```js
    <velt-huddle chat="false" flock-mode-onavatar-click="true"></velt-huddle>
    ```

    API Methods:

    ```jsx
    const huddleElement = client.getHuddleElement();
    // to enable flock mode on avatar click
    huddleElement.enableFlockModeOnAvatarClick();
    // to disable flock mode on avatar click
    huddleElement.disableFlockModeOnAvatarClick();
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { VeltHuddle, VeltHuddleTool} from '@veltdev/react';
  import {useEffect} from 'react'

  export default function App() {

    useEffect(()=>{
      const huddleElement = client.getHuddleElement();
      huddleElement.enableChat();
      huddleElement.disableChat();
      huddleElement.enableFlockModeOnAvatarClick();
      huddleElement.disableFlockModeOnAvatarClick();
    })

    return (
      <VeltHuddle darkMode={true}/> 

      <div className="toolbar">
        <VeltHuddleTool type='audio' /> 
        <VeltHuddleTool type='video' /> 
        <VeltHuddleTool type='screen' /> 
        <VeltHuddleTool type='all' /> 
      </div>
    );
  }
  ```

  ```html HTML
  <div>
    <velt-huddle dark-mode='true'></velt-huddle>
    <div class="toolbar">
      <velt-huddle-tool type='audio'></velt-huddle-tool> 
      <velt-huddle-tool type='video'></velt-huddle-tool> 
      <velt-huddle-tool type='screen'></velt-huddle-tool> 
      <velt-huddle-tool type='all'></velt-huddle-tool> 
    </div>
  </div>
  <script>
    const huddleElement = client.getHuddleElement();
    huddleElement.enableChat();
    huddleElement.disableChat();
    huddleElement.enableFlockModeOnAvatarClick();
    huddleElement.disableFlockModeOnAvatarClick();
  </script>

  ```
</RequestExample>


# Overview

Enable slack-style effortless audio, video and screen sharing discussions inside your own product. It even comes with built in chat.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=huddle" scrolling="no" frameBorder="0" className="w-full" height="500px" allow="display-capture; camera; microphone;displayCapture;" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=huddle)


# Setup



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Huddle Component">
        Import the `Huddle` component from the React library.

        ```js
        import { VeltHuddle, VeltHuddleTool } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Huddle Component">
        Add the `VeltHuddle` component to the root of your app.

        ```js
        <VeltHuddle />
        ```

        This component is required to render `Huddle` UI components and `Huddle` users in your app.
      </Step>

      <Step title="Add Huddle Tool Component">
        Add the `VeltHuddleTool` component wherever you want to show the `Huddle` tool button.

        Clicking on it initiates a huddle.

        ```js
        <div className="toolbar">
              <VeltHuddleTool type='all' />
        </div>
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Place the <velt-huddle> component">
        Add the `VeltHuddle` component to the root of your app.

        This component is required to render `Huddle` UI components and `Huddle` users in your app.

        ```html
        <div>
          <velt-huddle></velt-huddle>
        </div>
        ```
      </Step>

      <Step title="Place the <velt-huddle-tool> component">
        Add the `VeltHuddleTool` component wherever you want to show the `Huddle` tool button.

        Clicking on it initiates a `Huddle`.

        ```html
        <div>
          <velt-huddle-tool></velt-huddle-tool>
        </div>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { VeltHuddle, VeltHuddleTool} from '@veltdev/react';

  export default function App() {

    return (
      <VeltHuddle /> {/* Add VeltHuddle at the root of your app */}

      <div className="toolbar">
        <VeltHuddleTool type='all' /> {/* Add VeltHuddleTool where you want the huddle button to appear */}
      </div>
    );
  }
  ```

  ```html HTML
  <div>
    <velt-huddle></velt-huddle> <!-- Add velt-huddle component at the root of your app -->
    <velt-huddle-tool></velt-huddle-tool> <!-- Add velt-huddle-tool where you want the huddle button to appear-->
  </div>

  ```
</RequestExample>


# Customize Behavior



## 1. Enable/Disable Default Elements Tracking

*   When **enabled**,
    *   the SDK will track User's presence on these elements types automatically: `input`, `textarea`, `button`, `contenteditable`.
    *   to disable tracking on certain elements, you need to manually add an attribute `data-velt-live-selection-enabled="false"` to those elements.

*   When **disabled**,
    *   the SDK will not track User's presence on any elements.
    *   to enable tracking on certain elements, you need to manually add an attribute `data-velt-live-selection-enabled="true"` to those elements.

*   Default: `Enabled`.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    const selectionElement = client.getSelectionElement();

    selectionElement.enableDefaultElementsTracking();
    selectionElement.disableDefaultElementsTracking();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const selectionElement = Velt.getSelectionElement();

    selectionElement.enableDefaultElementsTracking();
    selectionElement.disableDefaultElementsTracking();
    ```
  </Tab>
</Tabs>

## 2. Enable/Disable User Indicator

*   User indicator is the user avatar or their name label that appears on the top left or top right of the selected element.
*   Default: `Enabled`.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    const selectionElement = client.getSelectionElement();

    selectionElement.enableUserIndicator();
    selectionElement.disableUserIndicator();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const selectionElement = Velt.getSelectionElement();

    selectionElement.enableUserIndicator();
    selectionElement.disableUserIndicator();
    ```
  </Tab>
</Tabs>

## 3. Set User Indicator Position

*   User indicator position can be set to `start` or `end`.

*   You can set it globally using API or set it locally on individual elements using attributes.

*   Default: `end`.

<Tabs>
  <Tab title="React / Next.js">
    Set globally using API:

    ```javascript
    const selectionElement = client.getSelectionElement();

    selectionElement.setUserIndicatorPosition('start');
    ```

    Set locally on individual elements using attributes:

    ```html
    <div data-velt-live-selection-user-indicator-position="start">...</div>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Set globally using API:

    ```javascript
    const selectionElement = Velt.getSelectionElement();

    selectionElement.setUserIndicatorPosition('start');
    ```

    Set locally on individual elements using attributes:

    ```html
    <div data-velt-live-selection-user-indicator-position="start">...</div>
    ```
  </Tab>
</Tabs>

## 4. Set User Indicator Type

*   User indicator type can be set to `avatar` or `label`.
    *   `avatar`: Displays the user avatar.
    *   `label`: Displays the user's name.

*   You can set the type globally using API or set it locally on individual elements using attributes.

*   Default: `avatar`.

<Tabs>
  <Tab title="React / Next.js">
    Set globally using API:

    ```javascript
    const selectionElement = client.getSelectionElement();

    selectionElement.setUserIndicatorType('label');
    ```

    Set locally on individual elements using attributes:

    ```html
    <div data-velt-live-selection-user-indicator-type="label">...</div>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Set globally using API:

    ```javascript
    const selectionElement = Velt.getSelectionElement();

    selectionElement.setUserIndicatorType('label');
    ```

    Set locally on individual elements using attributes:

    ```html
    <div data-velt-live-selection-user-indicator-type="label">...</div>
    ```
  </Tab>
</Tabs>

## 5. Get Live Selection Data

*   Get the live selection data for the current document.

    <Tabs>
      <Tab title="React / Next.js">
        **Using Hook:**

        ```jsx
          const liveSelectionData = useLiveSelectionDataHandler();

          useEffect(() => {
            console.log('liveSelectionData', liveSelectionData);
          }, [liveSelectionData]);
        ```

        **Using API:**

        ```javascript
          const selectionElement = client.getSelectionElement();
          selectionElement.getLiveSelectionData().subscribe((liveSelectionData: LiveSelectionData) => {
            console.log("liveSelectionData: ", liveSelectionData);
          });
        ```
      </Tab>

      <Tab title="Other Frameworks">
        **Using API:**

        ```javascript
          const selectionElement = Velt.getSelectionElement();
          selectionElement.getLiveSelectionData().subscribe((liveSelectionData: LiveSelectionData) => {
            console.log("liveSelectionData: ", liveSelectionData);
          });
        ```
      </Tab>
    </Tabs>


# Overview

Your users can see what part of the document others are interacting with in real-time.

When Live Selection is enabled, users will see the users' avatar or name, and a highlight box around the element they are interacting with.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=live-selection" className="w-full" height="500px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=live-selection)


# null



## Get the Live Selection Element and enable it

When enabled, Live Selection will automatically detect and highlight user's presence on the following elements:

*   `input`
*   `textarea`
*   `button`
*   `contenteditable`

You can learn more about customizing and controlling which elements are highlighted and its styling [here](/realtime-collaboration/live-selection/customize-behavior).

<Tabs>
  <Tab title="React / Next.js">
    ```js
    const { client } = useVeltClient();
    useEffect(() => {
      if (client) {
        const selectionElement = client.getSelectionElement();
        selectionElement.enableLiveSelection();
        selectionElement.disableLiveSelection();
      }
    }, [client]);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    if (Velt) {
      const selectionElement = Velt.getSelectionElement();
      selectionElement.enableLiveSelection();
      selectionElement.disableLiveSelection();
    }
    ```
  </Tab>
</Tabs>


# Overview

Allow users to sync state across forms in different clients

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=live-state-sync&layout=horizontal" scrolling="no" frameBorder="0" className="w-full" height="500px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=live-state-sync\&layout=horizontal)


# Redux Middleware



If you are using Redux, you can use our middleware to sync state changes directly into your Redux store.

<Steps>
  <Step title="Import the middleware">
    To get started import the `createLiveStateMiddleware` middleware from the Velt SDK.

    ```jsx
    import { createLiveStateMiddleware } from "@veltdev/react";
    ```
  </Step>

  <Step title="Add the middleware to your Redux store configuration">
    Use `createLiveStateMiddleware` to create a `middleware` and a `updateLiveStateDataId` method.

    Then add the created `middleware` to your Redux store configuration.

    You can also export the `updateLiveStateDataId` method from your Redux store. This method will be used to dynamically set the `liveStateDataId`.

    **store.js**:

    ```jsx
    import { configureStore } from "@reduxjs/toolkit";
    import { createLiveStateMiddleware } from "@veltdev/react";

    //create middleware
    const { middleware, updateLiveStateDataId } = createLiveStateMiddleware();

    //add middleware to your Redux store configuration
    export const store = configureStore({
      reducer: {
    	... your reducers here
      },
      // You just have to concat our liveStateMiddleware in store
      middleware: getDefaultMiddleware => getDefaultMiddleware().concat(middleware)
    });

    // optionally export updateLiveStateDataId method if you want to set liveStateDataId dynamically
    export { updateLiveStateDataId };
    ```
  </Step>

  <Step title="Optional Configurations">
    `createLiveStateMiddleware` takes in an optional configuration object with the following schema:

    ```tsx
    type LiveStateMiddlewareConfig = {
        allowedActionTypes?: Set<string>,
        disabledActionTypes?: Set<string>,
        allowAction?: (action: any) => boolean,
        liveStateDataId?: string,
    };
    ```

    You can use it to define the following fields:

    *   `allowedActionTypes` - allow live state syncing on specific action types only
    *   `disabledActionTypes` - restrict live state syncing on specific action types
    *   `allowAction` - custom callback method to dynamically decide to allow or disable syncing for that action. Return `true` to allow the action and `false` to restrict the action.
    *   `liveStateDataId` - used to set a custom string value as live state data key. If not provided, we will store data in default key.

    Example:

    ```jsx
    const { middleware, updateLiveStateDataId } = createLiveStateMiddleware({
    	allowedActionTypes: new Set(['action1', 'action2']),
    	disabledActionTypes: new Set(['disabledAction1', 'disabledAction2']),
    	allowAction: (action) => {
    		// return true to allow this action, false to restrict this action from syncing
        },
        liveStateDataId: 'custom-live-state-data-id'
    });
    ```

    <Info>
      It is recommended to first set a custom `liveStateDataId` in the middleware configuration. You can then change it dynamically later using the `updateLiveStateDataId` method.
    </Info>

    To set `liveStateDataId` dynamically, call the `updateLiveStateDataId` method that was previously created and exported from your store.

    ```jsx
    import { updateLiveStateDataId } from 'path-to-store.js';

    function YourComponent() {
    	
    	// You can update liveStateDataId any time based on your requirements and all the actions called after that will be synced on new ID path.
    	const setLiveStateDataId = (id) => {
    		updateLiveStateDataId(id);
        }

    	return (
            <div>Your HTML Template</div>
        );
    }
    ```
  </Step>
</Steps>

<RequestExample>
  ```jsx React / Next.js

  // store.js
  import { configureStore } from "@reduxjs/toolkit";
  import { createLiveStateMiddleware } from "@veltdev/react";

  //create middleware and updateLiveStateDataId method
  const { middleware, updateLiveStateDataId } = createLiveStateMiddleware({
  	allowedActionTypes: new Set(['action1', 'action2']),
  	disabledActionTypes: new Set(['disabledAction1', 'disabledAction2']),
  	allowAction: (action) => {
  		// return true to allow this action, false to restrict this action from syncing
      },
      liveStateDataId: 'custom-live-state-data-id'
  });

  //add middleware to your Redux store configuration
  export const store = configureStore({
    reducer: {
  	... your reducers here
    },
    // You just have to concat our liveStateMiddleware in store
    middleware: getDefaultMiddleware => getDefaultMiddleware().concat(middleware)
  });

  // you can optionally export the updateLiveStateDataId method if you want to set liveStateDataId dynamically
  export { updateLiveStateDataId };

  ```
</RequestExample>


# null



<Tabs>
  <Tab title="React / Next.js with Hooks">
    # Live State Sync

    With `Live State Sync`, you can create a shared data object that persists and syncs across all clients live on a given document.

    <Steps>
      <Step title="Import useLiveStateData, useSetLiveStateData, and useLiveState hooks">
        ```jsx
        import { useLiveStateData, useSetLiveStateData, useLiveState} from '@veltdev/react';
        ```
      </Step>

      <Step title="Set or Update a shared live data object">
        The `useSetLiveStateData()` hook can be used to set or update a custom shared data object that will be synced across all clients live on the current document.

        Pass in a unique ID and the data object you want to sync. If the object already exists with that ID, then it will be updated.

        Input params:

        *   `liveStateDataId`: `string`;
        *   `liveStateData`: `any`;

        ```jsx
        const liveStateDataId = 'uniqueId';
        const liveStateData = { 'key': 'value' }; // any type of data
        useSetLiveStateData(liveStateDataId, liveStateData)
        ```

        The hook will automatically unsubscribe from the subscription when the component dismounts.

        <Info>Data that is added via Live State Sync will persist until it is manually cleaned up. We don't auto reset the live state data after any period of time.</Info>
      </Step>

      <Step title="Get a shared live data object">
        The `useLiveStateData()` hook can be used to get the live state data object.

        Pass in the unique ID that you had used to set the data.

        Input params:

        *   `liveStateDataId`: `string`; (optional)

        ```jsx
        const liveStateDataId = 'uniqueId';
        let data = useLiveStateData(liveStateDataId)
        ```

        By default, the `useLiveStateData()` subscription will return all changes to the shared live data object including changes that occured when the current client was not subscribed.

        If you want to only receive changes starting from when the client subscribed to `useLiveStateData()`, you can pass a config object as shown below:

        ```jsx
        const liveStateDataConfig = {
        	listenToNewChangesOnly: true // default is false
        };

        const liveStateData = useLiveStateData(LIVE_STATE_DATA_KEY, liveStateDataConfig)
        ```
      </Step>

      <Step title="Sync Data Realtime">
        If you are familiar with React's `useState()` hook, we have a similar hook called `useLiveState()`  that can be used to sync data realtime for specific state variables in your code.

        Hook syntax:

        ```jsx
        const [value, setValue] = useLiveState(UNIQUE_ID, INITIAL_VALUE, OPTIONS);
        ```

        The hook takes in 3 parameters:

        *   `UNIQUE_ID` -> unique id in string to be synced across the screens
        *   `INITIAL_VALUE` -> initial value of the state
        *   `OPTIONS` (object)
            *   `syncDuration` -> debounce duration in milliseconds to sync realtime (optional, default value 50ms)
            *   `resetLiveState` -> Boolean to reset locatl state value on server side on initiatlize of hook (default: `false`)

        The hook returns a setter and getter:

        *   `value` -> current state value (similar to useState hook)
        *   `setValue` -> function to be called to set next value (similar to useState hook)

        Example:

        ```tsx
        import { useLiveState } from "@veltdev/react";

        export function MyReactComponent() {
          const [counter, setCounter] = useLiveState < number > ("counter", 0, {
            syncDuration: 100,
            resetLiveState: true
          });

          return (
            <div>
              <button onClick={() => setCounter((counter || 0) - 1)}>-</button>
              <span>Counter: {counter}</span>
              <button onClick={() => setCounter((counter || 0) + 1)}>+</button>
            </div>
          );
        }
        ```

        By default, `useLiveState()` will return all changes to the shared live data object including changes that occured when the current client was not subscribed.

        If you want to only receive changes starting from when the client subscribed to `useLiveState()`, you can pass a config object as shown below:

        ```jsx
        const [counter, setCounter] = useLiveState < number > ("counter", 0, {
          syncDuration: 100,
          resetLiveState: true,
          listenToNewChangesOnly: true // default is false
        });
        ```
      </Step>

      <Step title="Listen to Server Connection State Changes">
        You can listen to changes in the server connection state with the `useServerConnectionStateChangeHandler()` hook.

        ```jsx
        const serverConnectionState = useServerConnectionStateChangeHandler();
        ```

        The server connection state will be an ENUM with the following states:

        ```jsx
        export enum ServerConnectionState {
          ONLINE = 'online',
          OFFLINE = 'offline',
          PENDING_INIT = 'pendingInit',
          PENDING_DATA = 'pendingData',
        }
        ```

        The `useLiveState()` hook can also return the server connection state as the third return value.

        ```jsx
        import { useEffect } from 'react';
        import { useLiveState, useServerConnectionStateChangeHandler } from '@veltdev/react';

        function YourComponent() {

          const serverConnectionState = useServerConnectionStateChangeHandler();

          useEffect(() => {
            console.log('serverConnectionState', serverConnectionState);
          }, [serverConnectionState]);

          // Returning serverConnectionState in useLiveState
          const [stateValue, setStateValue, serverConnectionStateInLiveState] = useLiveState(STATE_KEY, INITIAL_VALUE);

          useEffect(() => {
            console.log('stateValue:', stateValue, 'serverConnectionStateInLiveState:', serverConnectionStateInLiveState);
          }, [stateValue, serverConnectionStateInLiveState]);

          return (
                // ... your component code
            );
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="React / Next.js">
    # Live State Sync

    With `Live State Sync`, you can create a shared data object that persists and syncs across all clients live on a given document.

    <Steps>
      <Step title="Get a liveStateSyncElement instance">
        You can get an instance of the `liveStateSyncElement` element by calling `client.getLiveStateSyncElement()`.

        ```jsx
        const { client } = useVeltClient();

        useEffect( () => {
          if(client){
            const liveStateSyncElement = client.getLiveStateSyncElement();
          }
        })
        ```

        Or you can use the `useLiveStateSyncUtils()` hook, which avoids a lot of boilerplate code:

        ```jsx
        const liveStateSyncElement = useLiveStateSyncUtils();
        ```
      </Step>

      <Step title="Set or Update a shared live data object">
        The `liveStateSyncElement.setLiveStateData()` method sets or updates a custom shared data object that will be synced across all clients live on the current document.

        Pass in a unique ID and the data object you want to sync. If the object already exists with that ID, then it will be updated.

        Input params:

        *   `liveStateDataId`: `string`;

        *   `liveStateData`: `any`;

        ```jsx
        const liveStateDataId = 'uniqueId';
        const liveStateData = { 'key': 'value' }; // any type of data
        liveStateSyncElement.setLiveStateData(liveStateDataId, liveStateData);
        ```

        <Info>Data that is added via Live State Sync will persist until it is manually cleaned up. We don't auto reset the live state data after any period of time.</Info>
      </Step>

      <Step title="Get a shared live data object">
        The `liveStateSyncElement.getLiveStateData()` method subscribes to an existing shared live data object. Pass in the unique ID that you had used to set the data.

        Input params:

        *   `liveStateDataId`: `string`; (optional)

        ```jsx
        const liveStateDataId = 'uniqueId';
        let subscription = liveStateSyncElement.getLiveStateData(liveStateDataId).subscribe((data) => {
        		// your logic here...
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        By default, the `getLiveStateData()` subscription will return all changes to the shared live data object including changes that occured when the current client was not subscribed.

        If you want to only receive changes starting from when the client subscribed to `getLiveStateData()`, you can pass a config object as shown below:

        ```jsx
        const liveStateDataConfig = {
        	listenToNewChangesOnly: true  // default is false
        };

        let subscription = liveStateSyncElement.getLiveStateData(LIVE_STATE_DATA_KEY, liveStateDataConfig).subscribe((data) => {
        	console.log('[Debug] getLiveStateData 31-05-2024-2 in html', data);
        });
        ```
      </Step>

      <Step title="Listen to Server Connection State Changes">
        You can listen to changes in the server connection state with the `onServerConnectionStateChange()` method:

        ```jsx
        const liveStateSyncElement = client.getLiveStateSyncElement();
        let subscription = liveStateSyncElement.onServerConnectionStateChange().subscribe((data) => {
          console.log('server connection state change: ', data);
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        The server connection state will be an ENUM with the following states:

        ```jsx
        export enum ServerConnectionState {
          ONLINE = 'online',
          OFFLINE = 'offline',
          PENDING_INIT = 'pendingInit',
          PENDING_DATA = 'pendingData',
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    # Live State Sync

    With `Live State Sync`, you can create a shared data object that persists and syncs across all clients live on a given document.

    <Steps>
      <Step title="Get a liveStateSyncElement instance">
        ```jsx
        const liveStateSyncElement = Velt.getLiveStateSyncElement();
        ```
      </Step>

      <Step title="Set or Update a shared live data object">
        The `liveStateSyncElement.setLiveStateData()` method sets or updates a custom shared data object that will be synced across all clients live on the current document.

        Pass in a unique ID and the data object you want to sync. If the object already exists with that ID, then it will be updated.

        Input params:

        *   `liveStateDataId`: `string`;

        *   `liveStateData`: `any`;

        ```jsx
        const liveStateDataId = 'uniqueId';
        const liveStateData = { 'key': 'value' }; // any type of data
        const liveStateSyncElement = Velt.getLiveStateSyncElement();
        liveStateSyncElement.setLiveStateData(liveStateDataId, liveStateData);
        ```

        <Info>Data that is added via Live State Sync will persist until it is manually cleaned up. We don't auto reset the live state data after any period of time.</Info>
      </Step>

      <Step title="Get a shared live data object">
        The `liveStateSyncElement.getLiveStateData()` method subscribes to an existing shared live data object. Pass in the unique ID that you had used to set the data.

        Input params:

        *   `liveStateDataId`: `string`; (optional)

        ```jsx
        const liveStateDataId = 'uniqueId';
        const liveStateSyncElement = Velt.getLiveStateSyncElement();
        let subscription = liveStateSyncElement.getLiveStateData(liveStateDataId).subscribe((data) => {
        		// your logic here...
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        By default, the `getLiveStateData()` subscription will return all changes to the shared live data object including changes that occured when the current client was not subscribed.

        If you want to only receive changes starting from when the client subscribed to `getLiveStateData()`, you can pass a config object as shown below:

        ```jsx
        const liveStateDataConfig = {
        	listenToNewChangesOnly: true // default is false 
        };

        liveStateSyncElement.getLiveStateData(LIVE_STATE_DATA_KEY, liveStateDataConfig).subscribe((data) => {
        	console.log('[Debug] getLiveStateData 31-05-2024-2 in html', data);
        });
        ```
      </Step>

      <Step title="Listen to Server Connection State Changes">
        You can listen to changes in the server connection state with the `onServerConnectionStateChange()` method:

        ```jsx
        const liveStateSyncElement = Velt.getLiveStateSyncElement();
        let subscription = liveStateSyncElement.onServerConnectionStateChange().subscribe((data) => {
          console.log('server connection state change: ', data);
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        The server connection state will be an ENUM with the following states:

        ```jsx
        export enum ServerConnectionState {
          ONLINE = 'online',
          OFFLINE = 'offline',
          PENDING_INIT = 'pendingInit',
          PENDING_DATA = 'pendingData',
        }
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js with Hooks
  import { useLiveStateData, useSetLiveStateData, useLiveState} from '@veltdev/react';

  export default function YourDocument() {


    const liveStateDataId = "uniqueId";
    const liveStateData = { "key": "value" }; // any type of data

    //sets the live state data object
    useSetLiveStateData(liveStateDataId, liveStateData)
    

    //Gets the live state data object
    let data = useLiveStateData("myUniqueId")

    //Setter and Getter for useLiveState, 
    //Third return value is an ENUM showing the connection state
    const [counter, setCounter, serverConnectionStateInLiveState] = useLiveState("counter", 0, {
      syncDuration: 100,
      resetLiveState: true
    });

    //Gets the server connection state
    const serverConnectionState = useServerConnectionStateChangeHandler();



    return (
      <div>
        {data?.myKey}
        <div>
          <button onClick={() => setCounter((counter || 0) - 1)}>-</button>
          <span>Counter: {counter}</span>
          <button onClick={() => setCounter((counter || 0) + 1)}>+</button>
        </div>
      </div>
    );
  }

  ```

  ```jsx React / Next.js
  import { useVeltClient, useEffect } from '@veltdev/react';

  export default function YourDocument() {
    const { client } = useVeltClient();

    useEffect(()=>{
      if(client){
          const liveStateDataId = "uniqueId";
          const liveStateData = { "key": "value" }; // any type of data
          const liveStateSyncElement = client.getLiveStateSyncElement();

          //Set Live State Data
          liveStateSyncElement.setLiveStateData(liveStateDataId, liveStateData);


          //Subscribe to Live State Data
          let subscription = liveStateSyncElement.getLiveStateData(liveStateDataId).subscribe((data) => {
          // your logic here...
          });

          // To unsubscribe from the subscription:
          subscription?.unsubscribe()

          //Subscribe to changes in server connection state
          liveStateSyncElement.onServerConnectionStateChange().subscribe((data) => {
            console.log('server connection state change: ', data);
          });

      }
    })


    return (
      <div>
        ...
      </div>
    );
  }

  ```

  ```jsx HTML

  if(Velt){
      const liveStateDataId = "uniqueId";
      const liveStateData = { "key": "value" }; // any type of data
      const liveStateSyncElement = Velt.getLiveStateSyncElement();

      //Set Live State Data
      liveStateSyncElement.setLiveStateData(liveStateDataId, liveStateData);

     
      //Subscribe to Live State Data
      let subscription = liveStateSyncElement.getLiveStateData(liveStateDataId).subscribe((data) => {
              // your logic here...
      });

      //To unsubscribe from the subscription:
      subscription?.unsubscribe()

      //Subscribe to changes in server connection state
      liveStateSyncElement.onServerConnectionStateChange().subscribe((data) => {
        console.log('server connection state change: ', data);
      });

  }
  ```
</RequestExample>


# Customize Behavior



<Tabs>
  <Tab title="React / Next.js">
    ## 1. Set inactivity time

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/inactivity.png)

    Set the time it takes for a `User` to go inactive in milliseconds.

    `Default: 300000ms (5 min)`

    ```js
    <VeltPresence inactivityTime={30000} />
    ```

    By default we mark a `User` as inactive if they do not take any action on the document within a 5 mins timeframe.

    If they unfocus the tab, we mark them inactive immediately.

    ## 2. Add Presence to a Location

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Location.png)

    Show  `Presence` on a `Location`.

    Set the `location` attribute on the `Presence` element. When there are `Users` at that location, their avatars will show in this `Presence` element.

    ```js
    <VeltPresence location={{page: 1}}/>
    ```

    Eg: For a Presentation tool, you can add `Presence` component at the main `document` level and add another `Presence` component on the slide thumbnails. This will render avatars at both presentation level & slide thumbnail level. For slide thumbnails, it will only show `Users` active on that slide.

    ## 3. Set max users

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Presence_Max_Users.png)

    Set how many `Presence` avatars to display at a time.

    You can set this via the `maxUsers` attribute. Any extra avatars will be hidden and shown in an avatar which indicates the number of extra `Users`.

    ```js
    <VeltPresence maxUsers={3} />
    ```

    ## 4. Enable Follow Me Mode

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Flock_Mode.png)

    To enable `Follow Me` Mode, set the `flockMode` attribute to `true`.

    ```js
    <VeltPresence flockMode={true} />
    ```

    This will enable `Follow Me mode` as an option for your `Users` globally, wherever Presence`is shown.`
    To start the shared flock session, click on a `User's` avatar to start following them.

    Learn more about it in the [Flock Mode feature section](/realtime-collaboration/flock-mode/overview).

    ## 5. Subscribe to changes in User Presence

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/onPresenceUserChange.png)

    Whenever the `Presence` for any `User` changes, we emit this event with the updated list of `Users` currently online on this document.

    ```js
    <VeltPresence onPresenceUserChange={(presenceUsers) => yourMethod(presenceUsers)} />
    ```

    ## 6. Dark Mode

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Mode.png)

    Whether dark mode is enabled.

    `Default: false`

    ```js
    <VeltPresence darkMode={true} />
    ```

    ## 7. Include Self in List of Presence Users

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/self.png)

    Whether to include yourself in the list of `Presence` users.

    `Default: true`

    ```js
    <VeltPresence self={false} />
    ```

    API Method:

    ```jsx
    const presenceElement = client.getPresenceElement();
    presenceElement.enableSelf();
    presenceElement.disableSelf();
    ```

    ## 8. Handle Presence User Click Events

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/onPresenceUserClick.png)

    To handle click events on `Presence` avatar circles, pass an event handler to the  `onPresenceUserClick` event.

    ```jsx
    const onPresenceUserClickEvent = (user) => {
      console.log("Clicked presence user: ", user);
    }
    	
    <VeltPresence onPresenceUserClick={(user) => onPresenceUserClickEvent(user)} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ## 1. Set inactivity time

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/inactivity.png)

    Set the time it takes for a `User` to go inactive.

    ```html
    <velt-presence inactivity-time="30000"></velt-presence>
    ```

    By default a `User` will go inactive after 5 minutes. If they unfocus the tab, then they will immediately go inactive.

    ## 2. Add Presence to a Location

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Location.png)

    Show  `Presence` on a `Location`.

    Set the `location` attribute on the `Presence` element. When there are `Users` at that location, their avatars will show in this `Presence` element.

    ```js
    <velt-presence location='{"page": 1}'></velt-presence>
    ```

    Eg: For a Presentation tool, you can add `Presence` component at the main `document` level and add another `Presence` component on the slide thumbnails. This will render avatars at both presentation level & slide thumbnail level. For slide thumbnails, it will only show `Users` active on that slide.

    ## 3. Set max users

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Presence_Max_Users.png)

    Max users determines how many Presence avatars to display at a time.

    You can set this via the max-users attribute. Any extra avatars will be hidden and shown in an avatar which indicates the number of extra `Users`.

    ```html
    <velt-presence max-users="3"></velt-presence>
    ```

    ## 4. Enable Follow Me Mode

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Flock_Mode.png)

    To enable `Follow Me Mode`, set the `flock-mode` attribute to `true`.

    ```html
    <velt-presence flock-mode="true"></velt-presence>
    ```

    This will enable `Follow Me mode` as an option for your `Users` globally, wherever Presence is shown.

    To start the shared `Follow Me` session, click on a `User's `avatar to start following them.

    Learn more about it in the [Flock Mode feature section](/realtime-collaboration/flock-mode/overview).

    ## 5. Subscribe to changes in User Presence

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/onPresenceUserChange.png)

    Whenever the `Presence` for any `User `changes, we emit the `onPresenceUserChange` event with the updated list of `Users` currently online on this document.

    ```js
    <script>
    if(Velt){
      const presenceElement = client.getPresenceElement();
      presenceElement.addEventListener('onPresenceUserChange', (event) => {
        console.log("onPresenceUserChange", event.detail);
      });
    }
    </script>
    ```

    ## 6. Dark Mode

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/Mode.png)

    Whether dark mode is enabled.

    `Default: false`

    ```js
    <velt-presence dark-mode="true"></velt-presence>
    ```

    ## 7. Include Self in List of Presence Users

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/self.png)

    Whether to include yourself in the list of `Presence` users.

    `Default: true`

    ```js
    <velt-presence self="false"></velt-presence>
    ```

    API Method:

    ```jsx
    const presenceElement = client.getPresenceElement();
    presenceElement.enableSelf();
    presenceElement.disableSelf();
    ```

    ## 8 . Handle Presence User Click Events

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/presence/onPresenceUserClick.png)

    To handle click events on `Presence` avatar circles, add an event listern on the `onPresenceUserClick` event.

    ```jsx
    const presenceTag = document.querySelector('velt-presence');
    	presenceTag.addEventListener('onPresenceUserClick', (event) => {
    		console.log("Clicked presence user: ", event.detail);
    });
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  import { VeltPresence, useVeltClient } from '@veltdev/react';
  import { useEffect } from 'react';

  export default function App() {
    let client = useVeltClient()

    const onPresenceUserClickEvent = (user) => {
      console.log("Clicked presence user: ", user);
    }


    useEffect(() => {
      if(client){
        const presenceElement = client.getPresenceElement();
        presenceElement.enableSelf(); // 7
        presenceElement.disableSelf(); // 7
      }

    })

    return (
      <div className="toolbar">
        <VeltPresence
          inactivityTime={30000} {/* 1) Set inactivity time */}
          location={{page: 1}} {/* 2) Add Presence to a Location */}
          maxUsers={3} {/* 3) Set max users */}
          flockMode={true} {/* 4) Enable Flock Mode */}
          onPresenceUserChange={(presenceUsers) => yourMethod(presenceUsers)} {/* 5) Subscribe to changes in User Presence */}
          darkMode={true} {/* 6) Dark Mode */}
          self={false} {/* 7) Disclude Self in list of Presence Users */}
          onPresenceUserClick={(user) => onPresenceUserClickEvent(user)} {/* 8) Handle Presence User Click Events */}
        />
      </div>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Presence documentation</title>
      <script>
      // 5) Subscribe to changes in User Presence
      if(Velt){
        const presenceElement = client.getPresenceElement();
        presenceElement.addEventListener('onPresenceUserChange', (event) => {
          console.log("onPresenceUserChange", event?.detail);
        });

       

        presenceElement.enableSelf(); // 7
        presenceElement.disableSelf(); // 7

         // 8) Subscribe to changes in User Presence
        const presenceTag = document.querySelector('velt-presence');
        presenceTag.addEventListener('onPresenceUserClick', (event) => {
          console.log("Clicked presence user: ", event.detail);
        });


      }
      </script>
    </head>
    <body>
      <div class="toolbar">
        <velt-presence
          inactivity-time="30000" <!-- 1) Set inactivity time -->
          location='{"page": 1}' <!-- 2) Add Presence to a Location -->
          max-users="3" <!-- 3) Set max users -->
          flock-mode='true' <!-- 4) Enable Flock Mode -->
          dark-mode='true' <!-- 6) Dark Mode -->
          self='false' <!-- 7) Dark Mode -->
        ></velt-presence> 
      </div>
    </body>
  </html>
  ```
</RequestExample>


# Overview

Your users can see other users online on the document. This makes your app feel alive.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=presence" scrolling="no" frameBorder="0" className="w-full" height="500px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=presence)


# Setup



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Import Presence Component">
        Import the `Presence` component from the React library.

        ```js
        import { VeltPresence } from '@veltdev/react';
        ```
      </Step>

      <Step title="Add Presence Component">
        Add it anywhere you want to see the `User` avatars.

        ```js
        <VeltPresence />
        ```

        This component renders the avatars of `Users` on the same document in your web app. We automactically detect when `Users` are active on the document and render their avatars.
      </Step>

      <Step title="Test Integration">
        Test it out by opening the target page in two browsers with two different `Users` logged in.

        You should see the avatars of the `Users` rendered where you added the `Presence` component.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Place the <velt-presence> component">
        Place the component wherever you want the avatars to appear.

        ```html
        <velt-presence></velt-presence>
        ```
      </Step>

      <Step title="Test Integration">
        Test it out by opening the target page in two browsers with two different `Users` logged in.

        You should see the avatars of the `Users` rendered where you added the `Presence` component.
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```js React
  import { VeltPresence } from '@veltdev/react';

  export default function App() {

    return (
      <div className="toolbar">
        <VeltPresence />
      </div>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Presence documentation</title>
    </head>
    <body>
      <div class="toolbar">
        <velt-presence></velt-presence>
      </div>
    </body>
  </html>
  ```
</RequestExample>


# Overview

Lock down forms or settings dashboards so only a single editor can edit at once.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=single-editor-mode&layout=horizontal" scrolling="no" frameBorder="0" className="w-full" height="500px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=single-editor-mode\&layout=horizontal)


# null



<Tabs>
  <Tab title="React / Next.js">
    ## Single Editor Mode

    With Single Editor Mode, only one user will be able to edit the document at any given time. All other users live on the document will automatically be read-only.

    <Steps>
      <Step title="Accessing the LiveStateSyncElement">
        The `LiveStateSyncElement` contains all of the methods used to interact with the `single editor mode` and `live state sync` features.

        There are two ways to access the `LiveStateSyncElement`.

        ### Accessing via the Velt client object

        ```jsx
        const liveStateSyncElement = client.getLiveStateSyncElement();
        ```

        ### Accessing via a hook

        ```jsx
        let liveStateSyncElement = useLiveSelectionUtils();
        ```
      </Step>

      <Step title="Enable Single Editor Mode">
        Enables single editor mode.

        `Disabled by default`

        ```jsx
        liveStateSyncElement.enableSingleEditorMode(); //enables single editor mode
        ```

        #### (Optional) Set your DOM to read-only yourself, or let our SDK do it for you.

        `Default: We handle it for you.`

        You can pass a configuration object to enable `customMode` on Single Editor Mode.

        If custom mode is enabled, we will not make the viewer's DOM read-only. You will have to handle the logic yourself.

        ```jsx
        liveStateSyncElement.enableSingleEditorMode({ customMode: true });
        ```

        #### (Optional) Lock Edit access to Single-Tab.

        `Default: true`

        The configuration `{singleTabEditor: boolean}` limits editing to one tab at a time. If an editor opens the same `document` in multiple tabs and begins editing in one (e.g., Tab 1), edit access is automatically disabled in the others (e.g., Tab 2). To enable editing in a different tab, a button can be implemented to trigger the `editCurrentTab()` method, granting edit access in that specific tab.

        ```tsx
        liveStateSyncElement.enableSingleEditorMode({ singleTabEditor: false });
        ```
      </Step>

      <Step title="Disable Single Editor Mode">
        Disables single editor mode.

        ```jsx
        liveStateSyncElement.disableSingleEditorMode(); // disables single editor mode
        ```
      </Step>

      <Step title="Enable default Single Editor UI">
        In Single Editor mode, by default there is a small toast at the bottom of the screen that shows:

        *   whether you are the editor or viewer
        *   whether any other viewer has requested editor access
        *   access request timeout coundown
        *   option to reject request

        To enable this toast, you can use the `enableDefaultSingleEditorUI()` method.

        `Default: enabled`

        ```jsx
        liveStateSyncElement.enableDefaultSingleEditorUI();
        ```
      </Step>

      <Step title="Disable default single editor UI">
        In Single Editor mode, by default there is a small toast at the bottom of the screen that shows:

        *   whether you are the editor or viewer
        *   whether any other viewer has requested editor access
        *   access request timeout coundown
        *   option to reject request

        You can choose to disable this toast in favor of using your own custom UI.

        To disable this pop up, you can use the `disableDefaultSingleEditorUI()` method.

        ```jsx
        liveStateSyncElement.disableDefaultSingleEditorUI();
        ```
      </Step>

      <Step title="Set current user as the Editor">
        Sets the current user as Editor. Note this will mark all the other users on the document as readonly users.

        ```jsx
        liveStateSyncElement.setUserAsEditor();
        ```
      </Step>

      <Step title="Check if current user is the Editor">
        `isUserEditor()` returns a subscription that emits the following `UserEditorAccess` object:

        ```jsx
        {
          isEditor: true, // `true` if the user is the editor  
          isEditorOnCurrentTab: true // true if the user is the editor on the current tab 
        }

        ```

        ```jsx
        let subscription = liveStateSyncElement.isUserEditor().subscribe((userEditorAccess) => {
          //userEditorAccess.isEditor <-- True if user is editor
          //userEditorAccess.isEditorOnCurrentTab <-- true if the user is editor on current tab
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        **Using Hooks:**

        The `useUserEditorState()` hook is used to call `liveStateSyncElement.isUserEditor()` without having to handle the subscription.

        The hook will automatically unsubscribe from the subscription when the component dismounts.

        ```jsx
        import { useUserEditorState} from '@veltdev/react';

        export default function YourDocument() {

          let {isEditor, isEditorOnCurrentTab} = useUserEditorState()
          console.log("Is User Editor?: ", isEditor)

          return (
            <div>
                Is User Editor?: {isEditor}
            </div>
          )
        }
        ```
      </Step>

      <Step title="Get the current editor">
        `getEditor()` returns a subscription that emits the `User` object representing the current editor.

        `User` object schema:

        ```jsx
        {
            "email": "userX@example.com",
            "name": "User X",
            "photoUrl": "https://i.pravatar.cc/302",
            "userId": "X",
        }
        ```

        ```jsx
        let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
          // user contains User object data

        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        **Using Hooks:**

        The `useEditor()` hook is used to call `liveStateSyncElement.getEditor()` without having to handle the subscription.

        The hook will automatically unsubscribe from the subscription when the component dismounts.

        ```jsx
        import { useEditor} from '@veltdev/react';

        export default function YourDocument() {

          let user = useEditor()
          console.log("Editor User Data: ", user)

          return (
            <div>
                Editor Email: {user.email}
                Editor Name: {user.name}
                Editor ID: {user.userId}
            </div>
          )
        }
        ```
      </Step>

      <Step title="Reset access for all users">
        Resets access for all users.

        ```jsx
        liveStateSyncElement.resetUserAccess();
        ```
      </Step>

      <Step title="Request editor access from the current editor">
        Call `requestEditorAccess()` from a Viewer's client to get editor access from the current editor.

        It returns a subscription that emits:

        *   `null` if the request is pending
        *   `true` if the request went accepted by the editor
        *   `false` if the request was rejected by the editor

        ```jsx
        let subscription = liveStateSyncElement.requestEditorAccess().subscribe((data) => {
        	// data == null -> Request is pending
        	// data == true -> Request accepted by editor
          // data == false -> Request rejected by editor
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>

      <Step title="Check whether editor access is being requested">
        The `isEditorAccessRequested()` method is used to detect on the `Editor's` client if a `Viewer` has requested editor access or not.

        <Info>
          If the user is not the editor or the request has been canceled, the subscription will emit a `null` value.
        </Info>

        It returns a subscription that emits:

        *   `null` if the user is not the editor or the request has been canceled
        *   a `isUserEditor` object if the user is the editor and there is an ongoing request

        `isUserEditor` Object Schema:

        ```jsx
        { 
          requestStatus: 'requested', // currently always is equal to 'requested' if there is an ongoing request
          requestedBy: { // User Object
            "email": "userX@example.com",
            "name": "User X",
            "photoUrl": "https://i.pravatar.cc/302",
            "userId": "X",
          }
        }
        ```

        ```jsx
        let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
          // data == null --> if user is not editor or the request has been canceled
          // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // data.requestedBy -> contains data about the User that requested access
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```

        **Using Hooks:**

        The `useEditorAccessRequestHandler()` hook is used to call `liveStateSyncElement.isEditorAccessRequested()` without having to handle the subscription.

        The hook will automatically unsubscribe from the subscription when the component dismounts.

        ```jsx
        import { useEditorAccessRequestHandler } from '@veltdev/react';

        export default function YourDocument= () {
        	const editorAccessRequested = useEditorAccessRequestHandler();


          // editorAccessRequested == null --> if user is not editor or the request has been canceled
          // editorAccessRequested.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // editorAccessRequestedrequestedBy -> contains data about the User that requested access


          return (
            <div>
                Editor Access Request status: {editorAccessRequested.requestStatus}

                Editor Access Requested by: {editorAccessRequested.requestedBy}
            </div>
          )
        }
        ```
      </Step>

      <Step title="Accept Editor access request">
        Once the Editor gets an Editor Access request, call 'acceptEditorAccessRequest()' method to `accept` the request.

        ```jsx
        liveStateSyncElement.acceptEditorAccessRequest();
        ```

        Use with `isEditorAccessRequested()`:

        ```jsx
        let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
          // data == null --> if user is not editor or the request has been canceled
          // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // data.requestedBy -> contains data about the User that requested access

          if(data.requestStatus === 'requested'){
            liveStateSyncElement.acceptEditorAccessRequest();
          }
        });
        ```
      </Step>

      <Step title="Reject Editor access request">
        Once the Editor gets an Editor access request, call 'rejectEditorAccessRequest()' method to `reject` the request.

        ```jsx
        liveStateSyncElement.rejectEditorAccessRequest();
        ```

        Use with `isEditorAccessRequested()`:

        ```jsx
        let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
          // data == null --> if user is not editor or the request has been canceled
          // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // data.requestedBy -> contains data about the User that requested access

          if(data.requestStatus === 'requested'){
            liveStateSyncElement.rejectEditorAccessRequest();
          }
        });
        ```
      </Step>

      <Step title="To cancel an edit access request by the Viewer">
        The `cancelEditorAccessRequest()` method is used to cancel an existing edit access request by the Viewer.

        ```jsx
        liveStateSyncElement.cancelEditorAccessRequest();
        ```
      </Step>

      <Step title="To make the current tab editable when the editor has opened multiple tabs">
        The `editCurrentTab()` method is used to make the current tab editable when the editor has opened multiple tabs on the same page.

        ```jsx
        liveStateSyncElement.editCurrentTab();
        ```
      </Step>

      <Step title="Setting timeout value for automatic editor access transfer after request">
        The `setEditorAccessTimeout()` method is used to set the editor access timeout value in seconds.

        `Default: 5 seconds`

        ```jsx
        liveStateSyncElement.setEditorAccessTimeout(15); // in seconds
        ```
      </Step>

      <Step title="Enable automatic transfer of edit access after timeout">
        The `enableEditorAccessTransferOnTimeOut()` method is used to enable automatic transferring of editor access after timeout.

        `Default: enabled`

        ```jsx
        liveStateSyncElement.enableEditorAccessTransferOnTimeOut();
        ```
      </Step>

      <Step title="Disable automatic transfer of edit access after timeout">
        The `disableEditorAccessTransferOnTimeOut()` method is used to disable automatic transferring of editor access after timeout.

        ```jsx
        liveStateSyncElement.disableEditorAccessTransferOnTimeOut();
        ```
      </Step>

      <Step title="Automatically sync contents of Text Elements">
        Auto syncs the content of the following Text HTML elements, such that when `editor` types, the element's content is synced across all active users currently live on the document.

        *   input
        *   textarea
        *   ContentEditable Divs

        To enable syncing, follow these two steps:

        1.  Enable Auto Sync State feature:

        ```jsx
        liveStateSyncElement.enableAutoSyncState();
        ```

        2.  Set the `data-velt-sync-state` attribute to `true` on the Text HTML element you want to sync:

        <Info>You can set an `id` to the HTML element to make the syncing more robust.</Info>

        ```jsx
        <textarea id="uniqueId" data-velt-sync-state="true"></textarea>
        ```

        <Warning>You must add the `data-velt-sync-state` attribute to a native HTML element (e.g. input, textarea). It will not work directly on React components.</Warning>
      </Step>

      <Step title="Automatically make HTML Elements readonly or editable">
        By default in Single Editor Mode, we control making these html elements editable or readonly on the entire DOM:

        *   input
        *   textarea
        *   select
        *   button
        *   contentEditable divs

        For Viewers, the default elements listed above will be disabled, meaning `click`, `mouseup` and `mousedown` events will be prevented.

        If there are any other elements that you want us to control beyond the default elements we listed above, such as `div`, `span` elements etc, then you can add `data-velt-sync-access="true"` to that element.

        ```jsx
        <div data-velt-sync-access="true"></div>
        ```

        <Warning>You must add the `data-velt-sync-access` attribute to native HTML elements (e.g. div, span). It will not work directly on React components.</Warning>
      </Step>

      <Step title="Exclude default HTML elements from Auto Syncing Access">
        In Single Editor Mode, we control enabling and disabling of certain html elements on the entire DOM.
        If you want to exclude any of those html elements from this behavior, you can add `data-velt-sync-access-disabled="true"` to that element.

        ```jsx
        <button data-velt-sync-access-disabled="true"></button>
        ```

        <Warning>You must add the `data-velt-sync-access-disabled` attribute to native HTML elements (e.g. button, input). It will not work directly on React components.</Warning>
      </Step>

      <Step title="Restrict Single Editor Mode to Specific Parent Containers">
        By default Single Editor Mode is enabled at <strong>the entire DOM</strong> level. You can restrict this feature to only certain HTML containers & their children by using the `singleEditorModeContainerIds()` method. It takes in an array of element ID strings. These IDs represent the parent elements within which Single Editor Mode will be enabled.

        ```jsx
        liveStateElement.singleEditorModeContainerIds(["rightPanel"]);
        ```
      </Step>

      <Step title="Get Editor Access Timer State">
        With the `useEditorAccessTimer` hook, you can get the Editor Access Timer state.

        ```jsx
        import { useEditorAccessTimer } from '@veltdev/react';

        function YourReactComponent {

            const editorAccessTimer = useEditorAccessTimer();

            useEffect(() => {
                if (editorAccessTimer?.state === 'completed') {
                    onEditorAccessTimerCompleted();
                }
            }, [editorAccessTimer]);

            const onEditorAccessTimerCompleted = () => {
                // If user is editor, make requester as editor
                acceptEditorAccessRequest();
                // If user is requester, make it as editor
                setUserAsEditor();
            }
        }
        ```

        The `editorAccessTimer` class has the following schema:

        *   `state`: `'idle'` | `'inProgress'` | `'completed' `
        *   `durationLeft`: `number`
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    ## Single Editor Mode

    With Single Editor Mode, only one user will be able to edit the document at any given time. All other users live on the document will automatically be read-only.

    <Steps>
      <Step title="Accessing the LiveStateSyncElement">
        The `LiveStateSyncElement` contains all of the methods used to interact with the `single editor mode` and `live state sync` features.

        ### Accessing via the Velt client object

        ```jsx
        const liveStateSyncElement = client.getLiveStateSyncElement();
        ```
      </Step>

      <Step title="Enable Single Editor Mode">
        Enables single editor mode.

        `Disabled by default`

        ```jsx
        liveStateSyncElement.enableSingleEditorMode(); //enables single editor mode
        ```

        #### (Optional) Set your DOM to read-only yourself, or let our SDK do it for you.

        `Default: We handle it for you.`

        You can pass a configuration object to enable `customMode` on Single Editor Mode.

        If custom mode is enabled, we will not make the viewer's DOM read-only. You will have to handle the logic yourself.

        ```jsx
        liveStateSyncElement.enableSingleEditorMode({ customMode: true });
        ```

        #### (Optional) Lock Edit access to Single-Tab.

        `Default: true`

        The configuration `{singleTabEditor: boolean}` limits editing to one tab at a time. If an editor opens the same `document` in multiple tabs and begins editing in one (e.g., Tab 1), edit access is automatically disabled in the others (e.g., Tab 2). To enable editing in a different tab, a button can be implemented to trigger the `editCurrentTab()` method, granting edit access in that specific tab.

        ```tsx
        liveStateSyncElement.enableSingleEditorMode({ singleTabEditor: false });
        ```
      </Step>

      <Step title="Disable Single Editor Mode">
        Disables single editor mode.

        ```jsx
        liveStateSyncElement.disableSingleEditorMode(); // disables single editor mode
        ```
      </Step>

      <Step title="Enable default Single Editor UI">
        In Single Editor mode, by default there is a small toast at the bottom of the screen that shows:

        *   whether you are the editor or viewer
        *   whether any other viewer has requested editor access
        *   access request timeout coundown
        *   option to reject request

        To enable this toast, you can use the `enableDefaultSingleEditorUI()` method.

        `Default: enabled`

        ```jsx
        liveStateSyncElement.enableDefaultSingleEditorUI();
        ```
      </Step>

      <Step title="Disable default single editor UI">
        In Single Editor mode, by default there is a small toast at the bottom of the screen that shows:

        *   whether you are the editor or viewer
        *   whether any other viewer has requested editor access
        *   access request timeout coundown
        *   option to reject request

        You can choose to disable this toast in favor of using your own custom UI.

        To disable this pop up, you can use the `disableDefaultSingleEditorUI()` method.

        ```jsx
        liveStateSyncElement.disableDefaultSingleEditorUI();
        ```
      </Step>

      <Step title="Set current user as the Editor">
        Sets the current user as Editor. Note this will mark all the other users on the document as readonly users.

        ```jsx
        liveStateSyncElement.setUserAsEditor();
        ```
      </Step>

      <Step title="Check if current user is the Editor">
        `isUserEditor()` returns a subscription that emits the following `UserEditorAccess` object:

        ```jsx
        {
          isEditor: true, // `true` if the user is the editor  
          isEditorOnCurrentTab: true // true if the user is the editor on the current tab 
        }

        ```

        ```jsx
        let subscription = liveStateSyncElement.isUserEditor().subscribe((userEditorAccess) => {
            // userEditorAccess.isEditor <-- True if user is editor
            // userEditorAccess.isEditorOnCurrentTab <-- true if the user is editor on current tab
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>

      <Step title="Get the current editor">
        `getEditor()` returns a subscription that emits the `User` object that represents the current editor.

        `User` object schema:

        ```jsx
        {
            "email": "userX@example.com",
            "name": "User X",
            "photoUrl": "https://i.pravatar.cc/302",
            "userId": "X",
        }
        ```

        ```jsx
        let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
          // user contains User object data
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>

      <Step title="Reset access for all users">
        Resets access for all users.

        ```jsx
        liveStateSyncElement.resetUserAccess();
        ```
      </Step>

      <Step title="Request editor access from the current editor">
        Call `requestEditorAccess()` from a Viewer's client to get editor access from the current editor.

        It returns a subscription that emits:

        *   `null` if the request is pending
        *   `true` if the request went accepted by the editor
        *   `false` if the request was rejected by the editor

        ```jsx
        let subscription = liveStateSyncElement.requestEditorAccess().subscribe((data) => {
        	// data == null -> Request is pending
        	// data == true -> Request accepted by editor
          // data == false -> Request rejected by editor
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>

      <Step title="Check whether editor access is being requested">
        The `isEditorAccessRequested()` method is used to detect on the Editor's client if a Viewer has requested editor access or not.

        <Info>
          If the user is not the editor or the request has been canceled, the subscription will emit a `null` value.
        </Info>

        It returns a subscription that emits:

        *   `null` if the user is not the editor or the request has been canceled
        *   a `isUserEditor` object if the user is the editor and there is an ongoing request

        `isUserEditor` Object Schema:

        ```jsx
        { 
          requestStatus: 'requested', // currently always is equal to 'requested' if there is an ongoing request
          requestedBy: { // User Object
            "email": "userX@example.com",
            "name": "User X",
            "photoUrl": "https://i.pravatar.cc/302",
            "userId": "X",
          }
        }
        ```

        ```jsx
        let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
          // data == null --> if user is not editor or the request has been canceled
          // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // data.requestedBy -> contains data about the User that requested access
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>

      <Step title="Accept Editor access request">
        Once the Editor gets an Editor Access request, call 'acceptEditorAccessRequest()' method to `accept` the request.

        ```jsx
        liveStateSyncElement.acceptEditorAccessRequest();
        ```

        Use with `isEditorAccessRequested()`:

        ```jsx
        let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
          // data == null --> if user is not editor or the request has been canceled
          // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // data.requestedBy -> contains data about the User that requested access

          if(data.requestStatus === 'requested'){
            liveStateSyncElement.acceptEditorAccessRequest();
          }
        });
        ```
      </Step>

      <Step title="Reject Editor access request">
        Once the Editor gets an Editor access request, call 'rejectEditorAccessRequest()' method to `reject` the request.

        ```jsx
        liveStateSyncElement.rejectEditorAccessRequest();
        ```

        Use with `isEditorAccessRequested()`:

        ```jsx
        liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
          // data == null --> if user is not editor or the request has been canceled
          // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // data.requestedBy -> contains data about the User that requested access

          if(data.requestStatus === 'requested'){
            liveStateSyncElement.rejectEditorAccessRequest();
          }
        });
        ```
      </Step>

      <Step title="To cancel an edit access request by the Viewer">
        The `cancelEditorAccessRequest()` method is used to cancel an existing edit access request by the Viewer.

        ```jsx
        liveStateSyncElement.cancelEditorAccessRequest();
        ```
      </Step>

      <Step title="To make the current tab editable when the editor has opened multiple tabs">
        The `editCurrentTab()` method is used to make the current tab editable when the editor has opened multiple tabs on the same page.

        ```jsx
        liveStateSyncElement.editCurrentTab();
        ```
      </Step>

      <Step title="Setting timeout value for automatic editor access transfer after request">
        The `setEditorAccessTimeout()` method is used to set the editor access timeout value in seconds.

        `Default: 5 seconds`

        ```jsx
        liveStateSyncElement.setEditorAccessTimeout(15); // in seconds
        ```
      </Step>

      <Step title="Enable automatic transfer of edit access after timeout">
        The `enableEditorAccessTransferOnTimeOut()` method is used to enable automatic transferring of editor access after timeout.

        `Default: enabled`

        ```jsx
        liveStateSyncElement.enableEditorAccessTransferOnTimeOut();
        ```
      </Step>

      <Step title="Disable automatic transfer of edit access after timeout">
        The `disableEditorAccessTransferOnTimeOut()` method is used to disable automatic transferring of editor access after timeout.

        ```jsx
        liveStateSyncElement.disableEditorAccessTransferOnTimeOut();
        ```
      </Step>

      <Step title="Automatically sync contents of Text Elements">
        Auto syncs the content of the following Text HTML elements, such that when `editor` types, the element's content is synced across all active users currently live on the document.

        *   input
        *   textarea
        *   ContentEditable Divs

        To enable syncing, follow these two steps:

        1.  Enable Auto Sync State feature:

        ```jsx
        liveStateSyncElement.enableAutoSyncState();
        ```

        2.  Set the `data-velt-sync-state` attribute to `true` on the Text HTML element you want to sync:

        <Info>You can set an `id` to the HTML element to make the syncing more robust.</Info>

        ```jsx
        <textarea id="uniqueId" data-velt-sync-state="true"></textarea>
        ```

        <Warning>You must add the `data-velt-sync-state` attribute to a native HTML element (e.g. input, textarea). It will not work directly on React components.</Warning>
      </Step>

      <Step title="Automatically make HTML Elements readonly or editable">
        By default in Single Editor Mode, we control making these html elements editable or readonly on the entire DOM:

        *   input
        *   textarea
        *   select
        *   button
        *   contentEditable divs

        For Viewers, the default elements listed above will be disabled, meaning `click`, `mouseup` and `mousedown` events will be prevented.

        If there are any other elements that you want us to control beyond the default elements we listed above, such as `div`, `span` elements etc, then you can add `data-velt-sync-access="true"` to that element.

        ```jsx
        <div data-velt-sync-access="true"></div>
        ```

        <Warning>You must add the `data-velt-sync-access` attribute to native HTML elements (e.g. div, span). It will not work directly on React components.</Warning>
      </Step>

      <Step title="Exclude default HTML elements from Auto Syncing Access">
        In Single Editor Mode, we control enabling and disabling of certain html elements on the entire DOM.
        If you want to exclude any of those html elements from this behavior, you can add `data-velt-sync-access-disabled="true"` to that element.

        ```jsx
        <button data-velt-sync-access-disabled="true"></button>
        ```

        <Warning>You must add the `data-velt-sync-access-disabled` attribute to native HTML elements (e.g. button, input). It will not work directly on React components.</Warning>
      </Step>

      <Step title="Restrict Single Editor Mode to Specific Parent Containers">
        By default Single Editor Mode is enabled at <strong>the entire DOM</strong> level. You can restrict this feature to only certain HTML containers & their children by using the `singleEditorModeContainerIds()` method. It takes in an array of element ID strings. These IDs represent the parent elements within which Single Editor Mode will be enabled.

        ```jsx
        liveStateElement.singleEditorModeContainerIds(["rightPanel"]);
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js

  //Get Velt Client
  import { useVeltClient } from '@veltdev/react';
  import { useEffect } from 'react';


  function MyComponent(){
      const { client } = useVeltClient();

      useEffect( () => {
          //Get LiveStateSyncElement from Velt Client
          const liveStateSyncElement = client.getLiveStateSyncElement();


          //Enable Single Editor Mode
          liveStateSyncElement.enableSingleEditorMode({
            customMode:false,
            singleTabEditor:true
          });

          //Disable Single Editor Mode
          liveStateSyncElement.disableSingleEditorMode();

          let subscription = liveStateSyncElement.isUserEditor().subscribe((userEditorAccess) => {
              //userEditorAccess.isEditor <-- True if user is editor
              //userEditorAccess.isEditorOnCurrentTab <-- true if the user is editor on current tab
          });

          let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
              // user contains User object data
          });

          //Set Current User as Editor
          liveStateSyncElement.setUserAsEditor();

          //Reset Editor Access
          liveStateSyncElement.resetUserAccess();

  	      //Enable Auto Sync State
          liveStateSyncElement.enableAutoSyncState();

          //Restrict Auto Sync Access to Specified Parent Elements
          liveStateSyncElement.singleEditorModeContainerIds(['element-1','element-2'])

          //Request editor access from the current editor
          let subscription = liveStateSyncElement.requestEditorAccess().subscribe((data) => {
              // data == null -> Request is pending
              // data == true -> Request accepted by editor
              // data == false -> Request rejected by editor
              
          });
         
          // Check whether editor access is being requested
          let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
              // data == null --> if user is not editor or the request has been canceled
              // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
              // data.requestedBy -> contains data about the User that requested access
              if(data.requestStatus === 'requested'){

                  // To accept an editor access request
                  liveStateSyncElement.acceptEditorAccessRequest();

                  // To reject an editor access request
                  liveStateSyncElement.rejectEditorAccessRequest();



              }

          });

          // To unsubscribe from the subscription:
          subscription?.unsubscribe();


          // Setting the editor access timeout value
          liveStateSyncElement.setEditorAccessTimeout(15); // in seconds

          // Enable automatic transfer of edit access after timeout
          liveStateSyncElement.enableEditorAccessTransferOnTimeOut();

          // Disable automatic transfer of edit access after timeout
          liveStateSyncElement.disableEditorAccessTransferOnTimeOut();

          // Enable single editor UI
          liveStateSyncElement.enableDefaultSingleEditorUI();

          // Disable single editor UI
          liveStateSyncElement.disableDefaultSingleEditorUI();

          // To cancel an edit access request by the Viewer
          liveStateSyncElement.cancelEditorAccessRequest();

          // To make the current tab editable when the editor has opened multiple tabs
          liveStateSyncElement.editCurrentTab();



      },[])
      return (
          <div>
              {/* Enable Auto Sync State across on Text Elements */}
              <textarea id="uniqueId" data-velt-sync-state="true"></textarea>
              {/* Enable Auto Sync Access on Custom Elements */}
              <div data-velt-sync-access="true"></div>
              {/* Disable Auto Sync Access on Default Elements */}
              <button data-velt-sync-access-disabled="true"></button>
          </div>
      )
  }

  ```

  ```js HTML
  <script>
  if(Velt){

      //Get LiveStateSyncElement from Velt Client
      const liveStateSyncElement = Velt.getLiveStateSyncElement();


      //Enable Single Editor Mode
      liveStateSyncElement.enableSingleEditorMode({
        customMode:false,
        singleTabEditor:true
      });

      //Disable Single Editor Mode
      liveStateSyncElement.disableSingleEditorMode();


      //Check if Current User is Editor
      let subscription = liveStateSyncElement.isUserEditor().subscribe((userEditorAccess) => {
          //userEditorAccess.isEditor <-- True if user is editor
          //userEditorAccess.isEditorOnCurrentTab <-- true if the user is editor on current tab
      });

      let subscription = liveStateSyncElement.getEditor().subscribe((user) => {
          // user contains User object data
      });

      //Set Current User as Editor
      liveStateSyncElement.setUserAsEditor();

      //Reset Editor Access
      liveStateSyncElement.resetUserAccess();

      //Enable Auto Sync State
      liveStateSyncElement.enableAutoSyncState();

      //Restrict Auto Sync Access to Specified Parent Elements
      liveStateSyncElement.singleEditorModeContainerIds(['element-1','element-2']);

      //Request editor access from the current editor
      let subscription = liveStateSyncElement.requestEditorAccess().subscribe((data) => {
          // data == null -> Request is pending
          // data == true -> Request accepted by editor
          // data == false -> Request rejected by editor
          
      });
      
      // Check whether editor access is being requested
      let subscription = liveStateSyncElement.isEditorAccessRequested().subscribe((data) => {
          // data == null --> if user is not editor or the request has been canceled
          // data.requestStatus == 'requested' -> Current user is Editor & access requested by Viewer
          // data.requestedBy -> contains data about the User that requested access
              if(data.requestStatus === 'requested'){

                  // To accept an editor access request
                  liveStateSyncElement.acceptEditorAccessRequest();

                  // To reject an editor access request
                  liveStateSyncElement.rejectEditorAccessRequest();
              }

          });

      // To unsubscribe from the subscription:
      subscription?.unsubscribe()


      // Setting the editor access timeout value
      liveStateSyncElement.setEditorAccessTimeout(15); // in seconds

      // Enable automatic transfer of edit access after timeout
      liveStateSyncElement.enableEditorAccessTransferOnTimeOut();

      // Disable automatic transfer of edit access after timeout
      liveStateSyncElement.disableEditorAccessTransferOnTimeOut();

      // Enable single editor UI
      liveStateSyncElement.enableDefaultSingleEditorUI();

      // Disable single editor UI
      liveStateSyncElement.disableDefaultSingleEditorUI();

      // To cancel an edit access request by the Viewer
      liveStateSyncElement.cancelEditorAccessRequest();

      // To make the current tab editable when the editor has opened multiple tabs
      liveStateSyncElement.editCurrentTab();

  }
  </script>
  <body>
      <!-- Enable Auto Sync State across on Text Elements -->
      <textarea data-velt-sync-state="true"></textarea>

      <!-- Enable Auto Sync Access on Custom Element -->
      <div data-velt-sync-access="true"></div>

      <!-- Disable Auto Sync Access on Default Elements -->
      <button data-velt-sync-access-disabled="true"></button>
  </body>
  ```
</RequestExample>


# null



## Video Player Sync

`Video Player Sync` allows users to sync their video player with other `Users` in the same document.

This lets all `Users` watch the same video at the same time.


# Setup



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step title="Add the data-sync-video-player attribute to your video player">
        To enable `Video Player Sync` in any video, add the `data-sync-video-player="true"` attribute to your video player.

        ```html
        <div>
            <video data-sync-video-player="true"></video>
        </div>
        ```
      </Step>

      <Step title="Test it out">
        Test out `Video Player Sync` by opening two clients side-by-side and having one client play the video player.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step title="Add the data-sync-video-player attribute to your video player">
        To enable `Video Player Sync` in any video, add the `data-sync-video-player="true"` attribute to your video player.

        ```html
        <div>
            <video data-sync-video-player="true"></video>
        </div>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js

  export default function App() {
    return (
      <div>
          <video data-sync-video-player="true"></video>
      </div>
    );
  }
  ```

  ```html HTML
  <div>
      <video data-sync-video-player="true"></video>
  </div>

  ```
</RequestExample>


# null



## Versions

*   Latest SDK: [1.0.107](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.119](https://www.npmjs.com/package/@veltdev/types)

## Method to Hide Comments from Users on specific Locations

The [client.excludeLocationIds()](https://docs.velt.dev/async-collaboration/comments/customize-behavior/general-controls) method can be used to hide `Comments` at specific `Locations` from `Users`.

```jsx
const locationIds = ['location1', 'location2']; // list of location ids
client.excludeLocationIds(locationIds);
```

## Configuration to Disable Recording Summaries

If you want to [disable the Recording summaries](https://docs.velt.dev/async-collaboration/comments/customize-behavior/multimedia) that appear when you record you audio, voice or screen, you can can now do so.

Example:

```jsx
<VeltComments recordingSummary={false} />
```

API Methods:

```jsx
const commentElement = client.getCommentElement();
// to show recording summary
commentElement.enableRecordingSummary();
// to hide recording summary
commentElement.disableRecordingSummary();
```

## Configuration to Disable Recording countdown

If you want to [disable the countdown](https://docs.velt.dev/async-collaboration/comments/customize-behavior/multimedia) that appears when you begin recording your audio, voice, or screen, you can now do so. When the countdown is disabled, recordings will begin instantly.

Example

```jsx
<VeltComments recordingCountdown={false} />
```

API Methods:

```jsx
// API method - comment element
const commentElement = client.getCommentElement();
// To enable recording countdown
commentElement.enableRecordingCountdown();
// To disable recording countdown
commentElement.disableRecordingCountdown();

// API method - recorder element
const recorderElement = client.getRecorderElement();
// To enable recording countdown
recorderElement.enableRecordingCountdown();
// To disable recording countdown
recorderElement.disableRecordingCountdown();
```

## Method to Remove the Document ID

You can now unset the `Document Id` to pause the Velt SDK functions.

```jsx
client.unsetDocumentId()
```

## More File Type Support in Comment attachments

We've added support for more file types in `Comment` attachments (`csv`, `docx`, `pptx`, `xlsx`, `webp`, `mp4` etc.).


# null



## Versions

*   Latest SDK: [1.0.112](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.127](https://www.npmjs.com/package/@veltdev/types)

## Option to Disable ShadowDOM

We've added an option for you to [disable the ShadowDOM on certain components](https://docs.velt.dev/async-collaboration/comments/customize-behavior/ui-controls).

By default, a ShadowDOM is used with certain components to ensure that your application's CSS does not interfere with the styling of the SDK components.

If you want your application's CSS to affect the styling of the SDK components, you can disable the ShadowDOM.

```jsx
<VeltComments pinShadowDom={false} dialogShadowDom={false} />
<VeltCommentsSidebar shadowDom={false} />
```

API methods:

```jsx
const commentElement = client.getCommentElement();
commentElement.enablePinShadowDOM();
commentElement.disablePinShadowDOM();
commentElement.enableDialogShadowDOM();
commentElement.disableDialogShadowDOM();
commentElement.enableSidebarShadowDOM();
commentElement.disableSidebarShadowDOM();
```

## Method to Unsubscribe from Subscriptions

We added an `unsubscribe()` method to unsubscribe from any event subscriptions.

Example subscription:

```jsx
let subscription = commentElement.getAllCommentAnnotations().subscribe((comments) => {
// Do something with comments
});
```

To unsubscribe from the subscription:

```jsx
subscription?.unsubscribe()
```

## Added webhook notifications for `Huddle` Create and Join Events

Your users will now receive [webhook notifications](https://docs.velt.dev/webhooks/huddle-webhooks) when a `Huddle` is created or joined.

Example notification schema:

```jsx
{
  "from": {
      // UserObject
  },
  "projectName": "string",
  "projectUrl": "string",
  "actionType": "string", // created | joined
  "notificationSource": "huddle",
  "documentId": "string",
  "clientDocumentId": "string",
  "id": "string",
  "timestamp": 1234567890,
  "actionUser": {
      // UserObject
  },
}
```

Click here to see the [Notification](https://docs.velt.dev/api-reference/models/Notification) schema.

## Added Validations to check for Audio and Video permissions on `Huddles`

Your users will now be prompted to check for Audio and Video permissions on `Huddles`

## Option to disable `Chat` feature on `Huddles`

You can now [disable the Chat feature](https://docs.velt.dev/realtime-collaboration/huddle/customize-behavior) that is enabled by default on `Huddle` component.

## Option to disable `flockMode` feature on `Huddles`

You can now [disable the flockMode feature](https://docs.velt.dev/realtime-collaboration/huddle/customize-behavior) that is enabled by default on `Huddle` component when clicking on another user's Avatar.

## Added support to set a custom order of locations to sort by in the `Comments Sidebar`.

You can now define the [order in which locations appear](https://docs.velt.dev/async-collaboration/comments-sidebar/customize-behavior) in the `Comments Sidebar` filter through the 'order' field in the `filterConfig` object.

```jsx
<VeltCommentsSidebar
  filterConfig={{
    location: {
      enable: true,
      name: 'Pages',
      enableGrouping: true,
      multiSelection: true,
      order: ['locationId1', 'locationId2', 'locationId3'] // pass array of location ids here
    },
  }}
/>
```

## Added configuration for Unread Comments Indicator

You can now configure the [Unread Comments Indicator](https://docs.velt.dev/async-collaboration/comments/customize-behavior/display-metadata) to be either `minimal` or `verbose`.

In `minimal` mode unread comments will be indicated by a small red dot.

In `verbose` mode unread comments will be indicated by a larger badge that says UNREAD

<Frame>
  ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/verbose-mode-comments.png)
</Frame>

## Added hook for `useUnsetDocumentId`

There is now a hook called [useUnsetDocumentId()](https://docs.velt.dev/api-reference/hooks/hooks#useunsetdocumentid) that calls [client.unsetDocumentId()](https://docs.velt.dev/api-reference/api-methods/velt-client)

```jsx
import { useUnsetDocumentId} from '@veltdev/react'
import React from 'react'

export default function YourComponent() {

  useUnsetDocumentId();

  return (
    <div>...</div>
  )
}
```

## Added option to use a specific version of the Velt React SDK.

You can now use a [specific version of the Velt React SDK](https://docs.velt.dev/get-started/setup/advanced).

To do so, in your `VeltProvider` component, set the `config` props object to `{ version: '1.0.XYZ' }`.

Example:

```jsx
<VeltProvider apiKey='YOUR_API_KEY' config={{ version: '1.0.126' }}>
	...
</VeltProvider>
```


# null



# 2.0.30

### New Features

*   \[**Comments**]: Added `resolvedByUserId` field on comment resolve. This allows tracking which user resolved a comment thread.

*   \[**Comments**]: Added a configuration on sidebar to open the filter panel as a bottom sheet (default) or overlap on the filter button.
    *   Prop: `filterPanelLayout`. Values: `'menu' | 'bottomSheet'` (default)
    *   Usage:

        <Tabs>
          <Tab title="React / Next.js">
            ```jsx
            <VeltCommentsSidebar filterPanelLayout="menu" />
            ```
          </Tab>

          <Tab title="Other Frameworks">
            ```html
            <velt-comments-sidebar filter-panel-layout="menu"></velt-comments-sidebar>
            ```
          </Tab>
        </Tabs>


# null



# 2.0.31

### New Features

*   \[**UI Customization**]: Added [Confirm Dialog Wireframe](/ui-customization/features/async/comments/confirm-dialog/overview) and added support for light and dark modes.
    *   This is a common UI component used for multiple features like deleting comment thread, deleting a recorded content and more.
    *   It will automatically inherit the light or dark mode property from the parent feature.


# null



# 2.0.33

### New Features

*   \[**UI Customization**]: Added conditional dynamic classes for different states of various interactive components:
    *   `velt-sidebar-tool-open`: For the sidebar button when the sidebar is open.
    *   `velt-notification-tool-open`: For the notification tool when the notification panel is open.
    *   `velt-comments-sidebar-status-open`: For the status dropdown trigger when the dropdown is open.
    *   `velt-comments-sidebar-filter-button-open`: For the filter button when the filter panel is open.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where after adding '@here' the cursor position was incorrectly placed at the start of the text.

# 2.0.32

### New Features

*   \[**UI Customization**]: Added conditional classes for different states of various interactive components:
    *   `velt-comment-pin-open`: For the comment pin when the pin is selected.
    *   `velt-dropdown-open`: For the dropdown trigger when the dropdown is open.
    *   `velt-assign-dropdown-open`: For the assign dropdown trigger when the dropdown is open.
    *   `velt-custom-dropdown-open`: For the custom dropdown trigger when the dropdown is open.
    *   `velt-options-dropdown-open`: For the options dropdown trigger when the dropdown is open.
    *   `velt-priority-dropdown-open`: For the priority dropdown trigger when the dropdown is open.
    *   `velt-status-dropdown-open`: For the status dropdown trigger when the dropdown is open.
    *   `velt-reaction-tool-open`: For the reaction tool when the tool is open.
    *   `velt-comment-bubble-open`: For the comment bubble when the bubble is selected.
    *   `velt-comment-bubble-hover`: For the comment bubble when the bubble is hovered over.

*   \[**Comments**]: Added configuration for customizing the '@here' mention label. eg: @all, @everyone, @team, etc:

    <Tabs>
      <Tab title="React / Next.js">
        Using Props:

        ```jsx
        <VeltComments atHereLabel="@all" />
        ```

        Using API:

        ```javascript
        const contactElement = client.getContactElement();
        contactElement.setAtHereLabel('@all');
        ```
      </Tab>

      <Tab title="Other Frameworks">
        Using Props:

        ```html
        <velt-comments at-here-label="@all"></velt-comments>
        ```

        Using API:

        ```javascript
        const contactElement = Velt.getContactElement();
        contactElement.setAtHereLabel('@all');
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Notifications**]: Various UI improvements on the notification panel.

### Bug Fixes

*   \[**Comments**]: Fixed a bug where email contacts could have an invalid character ('.') at the end.
*   \[**Comments**]: Resolved an issue where the comment sidebar filter wouldn't be sticky on page refresh.
*   \[**Debugger**]: Fixed typo with event name `commentMoreReplayOptionClicked` and updated it to `commentMoreReplyOptionClicked`.


# null



# 2.0.35

### Improvements

*   \[**Comments**]: Added dynamic `velt-composer-input-focused` class on the composer container whenever the input is focused.
    This provides more control over the styling of the composer input when it is focused.

# 2.0.34

### Improvements

*   \[**Comments**]: Added dynamic `velt-composer-open` class on the composer container whenever the composer is opened.

*   \[**Comments**]: Improved contact and reaction tooltips:
    *   Inherited shadow DOM property from parent's shadow DOM property.
    *   Added light mode and dark mode support.

### Bug Fixes

*   \[**Comments**]: Fixed user avatar background color in autocomplete chip tooltip to match the color assigned to the user in the SDK.


# null



# 2.0.39

### Bug Fixes

*   \[**Comments**]: Fixed a css padding issue related to the action buttons in the comment dialog composer.

# 2.0.38

## Bug Fixes

*   \[**Comments**]: Fixed an issue with the user-avatar component, ensuring it's consistently used across all the components.

# 2.0.37

### New Features

*   \[**Comments**]: Added the ability to exclude specific location IDs from the comments sidebar. This provides more control over the displayed content.

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltCommentsSidebar excludeLocationIds={['location1', 'location2']} />
    ```

    Using API:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.excludeLocationIdsFromSidebar(['location1', 'location2']);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-comments-sidebar exclude-location-ids='["location1", "location2"]'></velt-comments-sidebar>
    ```

    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.excludeLocationIdsFromSidebar(['location1', 'location2']);
    ```
  </Tab>
</Tabs>

# 2.0.36

### Improvements

*   \[**Comments**]: Applied `location` filters to the inline-comments-section component as well, following the same pattern like other comment components.
*   \[**UI Customization**]: Removed `!important` declarations from some component CSS, improving overall style flexibility and reducing potential conflicts.

### Bug Fixes

*   \[**Comments**]: Resolved an issue related to calculating comment pin positions, ensuring more accuracy and robustness.


# null



# 2.0.40

### Bug Fixes

*   \[**Comments**]: Fixed an issue related to `addContext` in the `onCommentAdd` event. This ensures that context is consistently added when a new comment is created.


# null



# 3.0.0

### Improvements

*   \[**Performance**]: Rewrote change detection and state management for the entire SDK to make it more performant. This is a major update and will benefit all developers.


# null



# 3.0.1

### New Features

*   \[**Comments**]: Added feature to render a comment bubble on the comment pin or triangle instead of the comment dialog. Hovering or clicking the bubble will open the comment dialog.

    *   `bubbleOnPin`: Whether to show bubble on pin \[default: false]
    *   `bubbleOnPinHover`: If the above is true, whether to show bubble when the pin is hovered over or clicked \[default: true]

    <Tabs>
      <Tab title="React / Next.js">
        Using Props:

        ```jsx
        <VeltComments bubbleOnPin={true} bubbleOnPinHover={false} />
        ```

        Using API:

        ```javascript
        const commentElement = client.getCommentElement();

        // To enable showing bubble on pin
        commentElement.enableBubbleOnPin();

        // To disable showing bubble on pin
        commentElement.disableBubbleOnPin();

        // To enable option to show bubble on pin hover vs only on click
        commentElement.enableBubbleOnPinHover();

        // To disable option to show bubble on pin hover
        commentElement.disableBubbleOnPinHover();
        ```
      </Tab>

      <Tab title="Other Frameworks">
        Using Props:

        ```html
        <velt-comments bubble-on-pin="true" bubble-on-pin-hover="false"></velt-comments>
        ```

        Using API:

        ```javascript
        const commentElement = Velt.getCommentElement();

        // To enable showing bubble on pin
        commentElement.enableBubbleOnPin();

        // To disable showing bubble on pin
        commentElement.disableBubbleOnPin();

        // To enable option to show bubble on pin hover vs only on click
        commentElement.enableBubbleOnPinHover();

        // To disable option to show bubble on pin hover
        commentElement.disableBubbleOnPinHover();
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Comments**]: Increased the max allowed size of attachments in composer from 2MB to 15MB.
*   \[**Comments**]: Decreased the size of triangle in comment pin from 15px to 10px.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where the comment dialog composer user avatar wireframe was not working.
*   \[**Comments**]: Resolved minor signal-related issues.
*   \[**Comments**]: Fixed Comment Dialog Attachments and Recording UI for inline comment mode, addressing aspect ratio issues.


# null



# 2.0.27

### Bug Fixes

*   \[**Comments**]: Fixed an issue with changes detection in the text comment feature.

# 2.0.26

### Improvements

*   \[**Notifications**]: Renamed Notification panel "all read" container wireframe components for better clarity and consistency:
    <Warning>This is a breaking change.</Warning>
    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        // Old
        <VeltNotificationsPanelWireframe.AllReadContainer />

        // New
        <VeltNotificationsPanelWireframe.Content.AllReadContainer />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <!-- Old -->
        <velt-notifications-panel-all-read-container-wireframe></velt-notifications-panel-all-read-container-wireframe>

        <!-- New -->
        <velt-notifications-panel-content-all-read-container-wireframe></velt-notifications-panel-content-all-read-container-wireframe>
        ```
      </Tab>
    </Tabs>

# 2.0.25

### New Features

*   \[**Comments**]: For [Custom Comment Annotation dropdown](/async-collaboration/comments/customize-behavior/custom-lists#1-add-custom-lists-on-comment-annotation) on comment dialog:
    *   Added a default placeholder for the custom dropdown and made it configurable.
    *   Added it to the composer by default.

```jsx
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: 'Custom Placeholder',
    data: customList, // your customList data here
};
```

<Tabs>
  <Tab title="React / Next.js with hooks">
    **Using Props:**

    ```jsx
    <VeltComments customListDataOnAnnotation={customListDataOnCommentAnnotation} />
    ```

    **Using API:**

    ```jsx
    const commentElement = useCommentUtils();		
    commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
    ```

    Using Wireframe:

    ```jsx
    <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Placeholder>
      Custom Placeholder
    </VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Placeholder>
    ```
  </Tab>

  <Tab title="React / Next.js">
    **Using Props:**

    ```jsx
    <VeltComments customListDataOnAnnotation={customListDataOnCommentAnnotation} />
    ```

    **Using API:**

    ```jsx
    const commentElement = client.getCommentElement();		
    commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
    ```

    Using Wireframe:

    ```jsx
    <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Placeholder>
      Custom Placeholder
    </VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Placeholder>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    **Using API:**

    ```jsx
    const commentElement = Velt.getCommentElement();			
    commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
    ```

    **Using Wireframe:**

    ```html
    <velt-comment-dialog-custom-annotation-dropdown-trigger-placeholder-wireframe>
      Custom Placeholder
    </velt-comment-dialog-custom-annotation-dropdown-trigger-placeholder-wireframe>
    ```
  </Tab>
</Tabs>

### Bug Fixes

*   \[**Comments**]: Fixed an issue related to `disableReactions` in comment dialog customization.


# null



# 2.0.29

### New Features

*   \[**Comments**]: Added feature to render a comment bubble on the comment pin or triangle instead of the comment dialog. Hovering or clicking the bubble will open the comment dialog.

    <Tabs>
      <Tab title="React / Next.js">
        Using props:

        ```jsx
        <VeltComments bubbleOnHover={true} />
        ```

        Using API:

        ```javascript
        const commentElement = client.getCommentElement();
        commentElement.showBubbleOnHover(); // Enable bubble on hover
        commentElement.hideBubbleOnHover(); // Disable bubble on hover
        ```
      </Tab>

      <Tab title="Other Frameworks">
        Using props:

        ```html
        <velt-comments bubble-on-hover="true"></velt-comments>
        ```

        Using API:

        ```javascript
        const commentElement = Velt.getCommentElement();
        commentElement.showBubbleOnHover(); // Enable bubble on hover
        commentElement.hideBubbleOnHover(); // Disable bubble on hover
        ```
      </Tab>
    </Tabs>

*   \[**Location**]: For multiple location setup, added support for using `data-velt-location-id` vs full location object for marking additional locations.

### Improvements

*   \[**Comments**]:Refactored comment components code for better maintainability.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where assignee banner text color was not being applied correctly for custom statuses.
*   \[**Notifications**]: Fixed an issue where the document name in the notifications documents tab was not being displayed correctly.

# 2.0.28

### New Features

*   \[**Notifications**]: Added ability to customize tabs on the Notifications Panel.

    <Tabs>
      <Tab title="React / Next.js with Hooks">
        ```jsx
        <VeltNotificationsTool tabConfig={{
            "forYou": {
                name: 'Custom For You',
                enable: true,
            },
            "documents": {
                name: 'Custom Documents',
                enable: true,
            },
            "all": {
                name: 'Custom All',
                enable: false,
            },
        }} />
        ```

        Using APIs:

        ```jsx
        const notificationElement = useNotificationUtils();

        const tabConfig = {
          "forYou": {
            name: 'Custom For You',
            enable: true,
          },
          "documents": {
            name: 'Custom Documents',
            enable: true,
          },
          "all": {
            name: "Custom All",
            enable: false,
          },
        };

        notificationElement.setTabConfig(tabConfig);
        ```
      </Tab>

      <Tab title="React / Next.js">
        ```jsx
        <VeltNotificationsTool tabConfig={{
            "forYou": {
                name: 'Custom For You',
                enable: true,
            },
            "documents": {
                name: 'Custom Documents',
                enable: true,
            },
            "all": {
                name: 'Custom All',
                enable: false,
            },
        }} />
        ```

        Using APIs:

        ```jsx
        const notificationElement = client.getNotificationElement();

        const tabConfig = {
          "forYou": {
            name: 'Custom For You',
            enable: true,
          },
          "documents": {
            name: 'Custom Documents',
            enable: true,
          },
          "all": {
            name: 'Custom All',
            enable: false,
          },
        };

        notificationElement.setTabConfig(tabConfig);
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```js
        const tabConfig = {
          "forYou": {
            name: 'Custom For You',
            enable: true,
          },
          "documents": {
            name: 'Custom Documents',
            enable: true,
          },
          "all": {
            name: 'Custom All',
            enable: false,
          },
        };

        const notificationsTool = document.querySelector('velt-notifications-tool');
        notificationsTool?.setAttribute("tab-config", JSON.stringify(tabConfig));
        ```

        Using APIs:

        ```jsx
        const notificationElement = Velt.getNotificationElement();

        const tabConfig = {
          "forYou": {
            name: 'Custom For You',
            enable: true,
          },
          "documents": {
            name: 'Custom Documents',
            enable: true,
          },
          "all": {
            name: 'Custom All',
            enable: false,
          },
        };

        notificationElement.setTabConfig(tabConfig);
        ```
      </Tab>
    </Tabs>

*   \[**@ mention**]: Added ability to override contact list on the client side. [Learn more](/async-collaboration/comments/customize-behavior/@mentions).
    *   The `merge` parameter is used to determine if the new contact list should be merged with the existing contact list or replaced. Default: `false`.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    ```jsx
    const contactElement = useContactUtils();

    useEffect(() => {
      contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: true});
    }, [contactElement]);

    ```
  </Tab>

  <Tab title="React / Next.js">
    ```jsx
    const contactElement = client.getContactElement();
    contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: true});
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const contactElement = Velt.getContactElement();
    contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: true});
    ```
  </Tab>
</Tabs>

*   \[**Document**]: Added ability to set metadata on the document while setting the `documentId`.
    *   You can set any key/value pair in the metadata object. `documentName` is a special field that we use to display the document name in some Velt Components.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    ```jsx
    useSetDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>

  <Tab title="React / Next.js">
    ```jsx
    const { client } = useVeltClient();

    useEffect(() => {
        if (client) {
            client.setDocument('unique-document-id', {documentName: 'Document Name'});
        }
    }, [client]);
    ```
  </Tab>

  <Tab title="HTML">
    ```jsx
    if(Velt){
        Velt.setDocument('unique-document-id', {documentName: 'Document Name'});
    }
    ```
  </Tab>

  <Tab title="Angular">
    ```jsx
    this.client.setDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>

  <Tab title="Vue.js">
    ```jsx
    client.setDocument('unique-document-id', {documentName: 'Document Name'});
    ```
  </Tab>
</Tabs>

### Improvements

*   \[**Comments**]: Improved the get comment annotations API to determine data loading state in React:
    ```jsx
    const [loading, setLoading] = useState(true);
    const commentAnnotations = useCommentAnnotations();

    useEffect(() => {
      if (commentAnnotations) {
        setLoading(false);
      } else {
        setLoading(true);
      }
    }, [commentAnnotations]);
    ```
*   \[**Core**]:Updated SDK CDN URL in React and Client libraries to point to `cdn.velt.dev`.


# null



## Summary

The new features in this release give you more control over the sidebar button, Recorder media options, reactions, and contact list.

## Enable Sidebar Button on Comment Dialog

By default, each Comment Dialog has a button at the bottom that will open the Comments Sidebar when clicked. You can now disable this button by setting the sidebarButtonOnCommentDialog prop to false.

## Subscribe to Sidebar Button Clicks on Comment Dialog

You can now subscribe to clicks on the Sidebar Button at the bottom of the Comment Dialog by passing a callback to the onSidebarButtonOnCommentDialogClick event handler.

## Set Recorder Media Options

You can now set the Recorder media options within Comments: (audio, screen, video, all, or none). By default, only audio recording is enabled. To set the Recorder media options, pass in a comma separated string of the features you want to enable.

## Enable Reactions

You can now enable or disable emoji reactions in Comments. By default, reactions are enabled.

## Add Comments on specific elements

You can now add a Comment on a specific element by ID. To do this, use the addCommentOnElement() API method and pass in an object with a specific schema.

## Reset Contact List using POST Method API

You can also replace an entire Group Ids contact list using a POST Method on the following API endpoint: `https://updatecontactlist-4mfhcuyw2q-uc.a.run.app`


# null



## Versions

*   Latest SDK: 1.0.83
*   Latest Types: 1.0.100

## Location Support in System Comments

Users can now specify location when adding a new comment using [System Comments](/api-reference/rest-apis/comments-feature/comment-annotations/add-comment-annotations).

```jsx
{
  "data": {
    "apiKey": "YOUR_API_KEY",
    "authToken": "YOUR_AUTH_TOKEN",
    "documentId": "snippyly-tinymce-13-oct",

		// You can pass location object to set comment to any specific location
		"location": {
			"locationName": "YOUR_LOCATION",
			// You can optionally pass version in location object
			// to show comment on specific version only
			// Note: if you set version then id and name fields are mandatory
			"version": {
				"id": "v1",
				"name": "Version 1"
			}
		},

    "targetElement": {
      "elementId": "systemCommentTest",
      "targetText": "we want our custom elements",
      "occurrence": 1
    },
    "commentData": [
      {
        "commentText": "Replace: dolor sit amet consectetur adipisicing elit with this is test comment",
        "replaceContentHtml": "this is <strong style='color: blue'>bold text</strong> test comment",
        "from": {
          "email": "test@velt.dev",
          "name": "Test User"
        }
      }
    ]
  }
}
```

## Comment Read Receipts

Newly added comments that have not been seen by Users will now display with a small red dot.

<Frame>
  <iframe width="700px" height="400px" src="https://www.youtube.com/embed/u2VcZe5QKA8?si=qyzP4CVuAt9wVz_l" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" />
</Frame>

## Specifying where comments are allowed using Class Names and Query Selectors

Expanded options for specifying where comments are allowed using class names and query selectors in addition to ids.

Added the `allowedElementClassNames` and `allowedElementQuerySelectors` properties on the `<VeltComments/>` component to provide more flexibility in determining where comments can be placed.

[See Docs](/async-collaboration/comments/customize-behavior/general-controls)

HTML:

```html
<velt-comments
  allowed-element-class-names='["class-name-1", "class-name-2"]'
  allowed-element-query-selectors='["#id1.class-name-1"]'
></velt-comments>
```

React:

```jsx
<VeltComments
  allowedElementClassNames={["class-name-1", "class-name-2"]}
  allowedElementQuerySelectors={["#id1.class-name-1"]}
/>;
```

API Methods:

```jsx
const commentElement = client.getCommentElement();
commentElement.allowedElementClassNames(["class-name-1", "class-name-2"]);
commentElement.allowedElementQuerySelectors(["#id1.class-name-1"]);
```

<Frame>
  <iframe width="700px" height="400px" src="https://www.youtube.com/embed/ERs2BYP84RA?si=O2qnAlNDhdFvIJQA" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" />
</Frame>


# null



## Versions

*   Latest SDK: 1.0.84
*   Latest Types: 1.0.101

## Option to Remove Comment Tool from Velt Video Player

We have introduced a new option to the [Velt Video Player](/async-collaboration/comments/setup/video-player-setup/video-player-setup) component, allowing users to remove the Comment Tool. This feature offers greater flexibility in customizing the player interface according to your specific needs.

<Frame caption="Velt Video Player with Comment Tool Enabled">
  ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool-velt-video-player.png)
</Frame>

To remove the `Comment Tool` from the `VeltVideoPlayer` control panel, set the `commentTool` property to `false`.

```jsx
<VeltVideoPlayer commentTool={false} />
```

## View Analytics Component

Introducing the [View Analytics](/async-collaboration/view-analytics/overview) component, a powerful tool for tracking visitor engagement with your documents. Simply integrate this component into your project to gain insights into document viewership. Customize it to display visitor data tailored to specific locations, enhancing your analytics capabilities.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=view-analytics" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="400px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=view-analytics)

## React Hooks Integration

We're excited to announce the addition of custom [React Hooks](/api-reference/hooks/hooks) to our SDK, streamlining the development process for our users. These hooks provide an alternative method for interacting with the SDK, offering a smoother developer experience. By utilizing hooks, you can access SDK functionalities without the need for additional wrappers, such as useEffect hooks. This enhancement simplifies your codebase and improves overall efficiency.

<Tabs>
  <Tab title="Example with Hooks">
    ```jsx
    import { useSetDocumentId } from '@veltdev/react';

    export default function YourDocument() {

      useSetDocumentId("my-document-id")

      return (
        <div>
            Your Document Template
        </div>
      )
    }
    ```
  </Tab>

  <Tab title="Example without Hooks">
    ```jsx

    import { useVeltClient } from '@veltdev/react';
    import { useEffect, useState } from 'react';

    export default function YourDocument() {

      const { client } = useVeltClient();


      useEffect(() => {
        if (client) {
          client.setDocumentId('unique-document-id');
        }
      }, [client]);

      return (
        <div>
          Your Document Template 
        </div>
        
      );
    }
    ```
  </Tab>
</Tabs>


# null



## Versions

*   Latest SDK: [1.0.87](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.103](https://www.npmjs.com/package/@veltdev/types)

## Comment Thread Component

We've abstacted out the UI we use for the threads in our `Comments`component into its own component. Now you can use our [Comment Thread](/async-collaboration/comment-thread/overview) component with your comment data to create your own custom UIs.

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=comment-thread" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=comment-thread)

## Update Contact List

The [Contact List](/users/client-side/setup) is the list of emails you see when you try to `@mention` one of your teammates in a comment thread.

We now have two ways for you to keep your users' contact lists up to date.

*   [Server Side](/users/server-side/api-reset-contact-list): Implement updates to your contact lists directly through a server-side API call. This method ensures that your contact lists are always synchronized with the latest data.
*   [Client Side](/users/client-side/setup): For more dynamic updates, the client-side `identify()` method can be re-called with a configuration object to reinitialize your logged in users' contact list.

## PDF Viewer Support

We've added support for you to [leave comments on PDF Viewers](/async-collaboration/comments/customize-behavior/general-controls). To enable this, simply add the `data-velt-pdf-viewer` attribute on the element containing your PDF.

```jsx
<!-- Add data-velt-pdf-viewer="true" attribute at container level of your pdf viewer -->
<div id="viewerContainer" data-velt-pdf-viewer="true">
    <!-- Your pdf viewer here -->
    <div id="viewer" class="pdfViewer"></div>
</div>
```


# null



## Summary

These new features are designed to improve the collaboration experience in Velt by making it easier for users to work together on documents. Single Editor Mode can be used to prevent conflicts when multiple users are editing the same document, and Text Element Sync can be used to keep everyone in sync with the latest changes to text-based elements. These features are in beta.

## Single Editor Mode

### This feature allows you to make it so that only one user can be editing elements on the document at the same time.

*   To enable single editor mode, use the enableSingleEditorMode() method.
*   To disable single editor mode, use the disableSingleEditorMode() method.
*   To check if the current user is the editor in single editor mode, subscribe to the isUserEditor\$() event.
*   To set the current user as the editor in single editor mode, use the setUserAsEditor() method.
*   To reset editor access in single editor mode, use the resetUserAccess() method.

## Text Element Sync

### This feature allows you to sync Input-type elements so when one user types, it gets filled for other users viewing the element.

*   To allow Input, Textarea or Contentedible elements to sync across clients, set the data-velt-sync-state attribute to true on the element you are trying to sync.
*   To disable clicks on elements, set the data-velt-sync-access attribute to false on the element you are trying to disable.


# null



## Versions

*   Latest React SDK: [1.0.160](https://www.npmjs.com/package/@veltdev/react)
*   Latest Non-React SDK: [1.0.160](https://www.npmjs.com/package/@veltdev/client)
*   Latest Types:  [1.0.178](https://www.npmjs.com/package/@veltdev/types)

## Added Email ID Validation in Token

We have introduced email ID validation. This enhancement ensures that the email provided in the token matches the email used during the user identification process (identify call), adding an extra layer of security to prevent user impersonation.


# null



## Versions

*   Latest React SDK: [1.0.162](https://www.npmjs.com/package/@veltdev/react)
*   Latest Non-React SDK: [1.0.162](https://www.npmjs.com/package/@veltdev/client)
*   Latest Types:  [1.0.180](https://www.npmjs.com/package/@veltdev/types)

## Added "velt-comment-pin" Component

We have introduced the velt-comment-pin component. You can use the Comment Pin component to manually set the position of a Comment Annotation.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentPin annotationId="-O0OL9H7ukfuXQe4Xtgk" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comment-pin annotation-id="-O0OL9H7ukfuXQe4Xtgk"></velt-comment-pin>
    ```
  </Tab>
</Tabs>


# null



## Versions

*   Latest React SDK: [2.0.0](https://www.npmjs.com/package/@veltdev/react)
*   Latest Non-React SDK: [2.0.0](https://www.npmjs.com/package/@veltdev/client)
*   Latest Types:  [2.0.0](https://www.npmjs.com/package/@veltdev/types)

## Added Shadow Dom Support in Notification and Video Component

We have now added Shadow DOM support in both the notification (for notification panel and notification tool) and video components.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltNotificationsTool shadowDom={false} panelShadowDom={false} />

    <VeltNotificationsPanel shadowDom={false} />

    <VeltVideoPlayer shadowDom={false} />

    <VeltCommentPlayerTimeline shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-video-player shadow-dom="false"></velt-video-player>

    <velt-comment-player-timeline shadow-dom="false"></velt-comment-player-timeline>

    <velt-notifications-tool shadow-dom="false" panel-shadow-dom="false"></velt-notifications-tool>

    <velt-notifications-panel shadow-dom="false"></velt-notifications-panel>
    ```
  </Tab>
</Tabs>


# null



## Versions

*   Latest React SDK: [2.0.3](https://www.npmjs.com/package/@veltdev/react)
*   Latest Non-React SDK: [2.0.3](https://www.npmjs.com/package/@veltdev/client)
*   Latest Types:  [2.0.3](https://www.npmjs.com/package/@veltdev/types)

## Added `selectCommentByAnnotationId` Method in Comment Element

A new method [`selectCommentByAnnotationId`](/api-reference/api-methods/comments#selectcommentbyannotationid) has been added to the comment element, allowing you to select a comment based on its annotation ID.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.selectCommentByAnnotationId("COMMENT_ANNOTATION_ID");
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.selectCommentByAnnotationId("COMMENT_ANNOTATION_ID");
    ```
  </Tab>
</Tabs>


# null



## Versions

*   Latest SDK: [1.0.147](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.164](https://www.npmjs.com/package/@veltdev/types)

## Updated JWT Token to include user properties such as groupId and isAdmin

We updated the body that is sent to the `https://api.velt.dev/v1/auth/token/get` [JWT Token endpoint](/security/jwt-tokens) to include user properties such as `groupId` and `isAdmin`.

The `groupId` field is used to validate that the `groupId` provided in the `identify` call is the same as the one passed to the JWT Token.

The `isAdmin` field is used to set a user as an `admin`.

| Field                    | Required | Description                                                                                                                          |
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `apiKey`                 | Yes      | Velt API Key                                                                                                                         |
| `authToken  `            | Yes      | Auth Token from the Velt console                                                                                                     |
| `userId `                | Yes      | Unique user id of the user                                                                                                           |
| `userProperties.groupId` | No       | If `groupId` is provided, it will be validated with the groupId used in the identify call. Recommended if you are setting `groupIds` |
| `userProperties.isAdmin` | No       | Set to `true` if you want to set user as `admin`. This is the only way to set a user as an `admin` User                              |

```jsx
{
  "data": {
    "apiKey": "YOUR_API_KEY", //Velt API Key
    "authToken": "YOUR_AUTH_TOKEN", // Auth Token from the Velt console
    "userId": "yourUserId", // unique user id of the user you are generating a JWT Token for
    "userProperties": {
        groupId: "YOUR_USER_GROUP_ID", // If groupId is provided here then we will validate it with the groupId used in the identify call
        isAdmin: true, // Set to true if you want to set user as admin
    }
  }
}
```

## Option to force re-login user on identify call

By default when you [identify](/get-started/setup/authenticate) a user, we maintain the user auth in the browser unless you explicitly change the logged in user with another identify call.

If you are granting a user additional access or have changed some metadata about the user and want those changes to be reflected immediately, then you should re-call the identify method with `forceReset` set to `true`.

```jsx
await client.identify(user, {
  forceReset: true
});
```


# null



## Versions

*   Latest React SDK: [1.0.158](https://www.npmjs.com/package/@veltdev/react)
*   Latest Non-React SDK: [1.0.158](https://www.npmjs.com/package/@veltdev/client)
*   Latest Types: [1.0.178](https://www.npmjs.com/package/@veltdev/types)

## Added `onContactSelected` API Method

We have introduced the [`onContactSelected`](/api-reference/api-methods/velt-client#oncontactselected) API method in the Contact Element. This new method allows organization clients to add selected users to their organization or document-level IAM directly.

API Method:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const contactElement = client.getContactElement();

    contactElement.onContactSelected().subscribe((data: any) => {
      console.log('contact selected: ', data);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const contactElement = Velt.getContactElement();

    contactElement.onContactSelected().subscribe((data: any) => {
      console.log('contact selected: ', data);
    });
    ```
  </Tab>
</Tabs>

React Hook:

```jsx
import React, { useEffect } from 'react';
import { useContactUtils, useContactSelected } from '@veltdev/react';

function YourComponent() {

  const contactUtils = useContactUtils();

  useEffect(() => {
    console.log('contactUtils: ', contactUtils);
  }, [contactUtils]);

  const onContactSelected = useContactSelected();

  useEffect(() => {
    console.log('onContactSelected: ', onContactSelected);
  }, [onContactSelected]);

  return (
    // Your component code
  );

}
```

API Method Response Payload:

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


# null



## Versions

*   Latest React SDK: [1.0.159](https://www.npmjs.com/package/@veltdev/react)
*   Latest Non-React SDK: [1.0.159](https://www.npmjs.com/package/@veltdev/client)
*   Latest Types: [1.0.177](https://www.npmjs.com/package/@veltdev/types)

## Added `organizationGroups` Support in Contacts and Autocomplete Feature

Within the contacts and autocomplete features we have added the support for `organizationGroups`.

## Added Various Methods in Contact Element

We have introduced three new methods in the Contact Element: [`enableAtHere`](/api-reference/api-methods/velt-client#enableathere), [`disableAtHere`](/api-reference/api-methods/velt-client#disableathere), and [`updateContactListScopeForOrganizationUsers`](/api-reference/api-methods/velt-client#updatecontactlistscopefororganizationusers).

API Methods:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const contactElement = client.getContactElement();
    // To enable @here for contact list
    contactElement.enableAtHere();
    // To disable @here for contact list
    contactElement.disableAtHere();
    /**
     * Update contact list scope for organization users.
     * @param scope ContactListScopeForOrganizationUsers[]
     */
    contactElement.updateContactListScopeForOrganizationUsers(['all', 'organization', 'organizationUserGroup', 'document']);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    const contactElement = Velt.getContactElement();
    // To enable @here for contact list
    contactElement.enableAtHere();
    // To disable @here for contact list
    contactElement.disableAtHere();
    /**
     * Update contact list scope for organization users.
     * @param scope ContactListScopeForOrganizationUsers[]
     */
    contactElement.updateContactListScopeForOrganizationUsers(['all', 'organization', 'organizationUserGroup', 'document']);
    ```
  </Tab>
</Tabs>


# null



## Versions

*   Latest React SDK: [2.0.4](https://www.npmjs.com/package/@veltdev/react)
*   Latest Non-React SDK: [2.0.4](https://www.npmjs.com/package/@veltdev/client)
*   Latest Types: [2.0.4](https://www.npmjs.com/package/@veltdev/types)

## Added REST APIs

We have added REST APIs so that developers have more control when it comes to accessing and setting data.

REST APIs is a featureset that will have continued expansion but the current REST APIs give improved control over **Organizations**, **Documents**, **Users**, **Organization User Groups**, and **Comments**.

More REST APIs will be coming soon!

### [Organizations APIs](/api-reference/rest-apis/organizations/add-organizations)

1.  Add Organizations
2.  Update Organizations
3.  Delete Organizations
4.  Get Organizations
5.  Update Disabled State for Organizations

### [Documents APIs](/api-reference/rest-apis/documents/add-documents)

1.  Add Documents
2.  Update Documents
3.  Delete Documents
4.  Get Documents
5.  Update Access for Documents
6.  Update Disabled State for Documents

### [Users APIs](/api-reference/rest-apis/users/add-users)

1.  Add Users
2.  Update Users
3.  Delete Users
4.  Get Users

### [Organization User Groups APIs](/api-reference/rest-apis/users/add-users)

1.  Add User Groups
2.  Add Users to Groups
3.  Delete Users from Groups

### [Commenting APIs](/api-reference/rest-apis/comments-feature/comment-annotations/add-comment-annotations)

1.  Add Comment Annotations
2.  Update Comment Annotations
3.  Delete Comment Annotations
4.  Get Comment Annotations
5.  Add Comments
6.  Update Comments
7.  Delete Comments
8.  Get Comments


# null



## Versions

*   Latest SDK: [1.0.144](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.161](https://www.npmjs.com/package/@veltdev/types)

# 1. Major Improvements to Comments Sidebar Customization

In this update, we made several improvements to the `Customization` of the `Comments Sidebar` and `Sidebar Button`

## Support for customizing additional Subcomponents within the Comments Sidebar and Sidebar Button

We modified or added support for customizing the following `subcomponents` of the `Comments Sidebar`:

*   [Filter](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/overview)
*   [Filter Category](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/category)
*   [Filter Close Button](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/close-button)
*   [Filter Done Button](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/done-button)
*   [Filter Item](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/filter-item)
*   [Filter Groupby](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/groupby)
*   [Filter Location](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/location)
*   [Filter People](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/people)
*   [Filter Priority](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/priority)
*   [Filter Title](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/title)
*   [Filter Versions](/ui-customization/features/async/comments/comments-sidebar/subcomponents/filter/subcomponents/versions)
*   [Header](/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/overview)
*   [Header Status](/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/status/overview)
*   [Header Status Trigger](/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/status/subcomponents/trigger)
*   [Header Status Content](/ui-customization/features/async/comments/comments-sidebar/subcomponents/header/subcomponents/status/subcomponents/content)
*   [List](/ui-customization/features/async/comments/comments-sidebar/subcomponents/list/overview)
*   [List Dialog Container](/ui-customization/features/async/comments/comments-sidebar/subcomponents/list/subcomponents/dialog-container)
*   [List Group](/ui-customization/features/async/comments/comments-sidebar/subcomponents/list/subcomponents/group)

We modified or added support for customizing the following `subcomponents` of the `Sidebar Button`:

*   [Sidebar Button](/ui-customization/features/async/comments/comments-sidebar/sidebar-button/overview)
*   [Sidebar Button Icon](/ui-customization/features/async/comments/comments-sidebar/sidebar-button/subcomponents/icon)

## Subcomponent Name Changes

We changed the names of several subcomponents:

*   `<VeltCommentsSidebarWireframe.List.Item.Annotation />` -> `<VeltCommentsSidebarWireframe.List.Item.DialogContainer />`

*   `<velt-comments-sidebar-list-item-annotation-wireframe>` -> `<velt-comments-sidebar-list-item-dialog-container-wireframe>`

The `Private Badge` subcomponent was moved from being a child of `Comment Dialog` to being a child of the `Comment Dialog Composer`:

*   `<VeltCommentDialogWireframe.PrivateBadge />`  -> `<VeltCommentDialogWireframe.Composer.PrivateBadge>`

*   `<velt-comment-dialog-private-badge-wireframe>` -> `<velt-comment-dialog-composer-private-badge-wireframe>`

# 2. Live State Sync changes

## `getLiveStateData()` now has a config option to only subscribe to new changes

By default, the [getLiveStateData()](/realtime-collaboration/live-state-sync/setup) subscription will return all changes to the shared live data object including changes that occured when the current client was not subscribed.

If you want to only receive changes starting from when the client subscribed to `getLiveStateData()`, you can pass a config object as shown below:

```jsx
const liveStateDataConfig = {
	listenToNewChangesOnly: true  // default is false
};

let subscription = liveStateSyncElement.getLiveStateData(LIVE_STATE_DATA_KEY, liveStateDataConfig).subscribe((data) => {
	console.log('[Debug] getLiveStateData 31-05-2024-2 in html', data);
});
```

This also applies to the `useLiveStateData()` hook:

```jsx
const liveStateDataConfig = {
	listenToNewChangesOnly: true // default is false
};

const liveStateData = useLiveStateData(LIVE_STATE_DATA_KEY, liveStateDataConfig)
```

As well as the `useLiveState()` hook:

```jsx
const [counter, setCounter] = useLiveState < number > ("counter", 0, {
  syncDuration: 100,
  resetLiveState: true,
  listenToNewChangesOnly: true // default is false
});
```

## Method to listen to changes in server connection state

You can listen to changes in the server connection state with the [onServerConnectionStateChange()](/realtime-collaboration/live-state-sync/setup) method:

```jsx
const liveStateSyncElement = client.getLiveStateSyncElement();
let subscription = liveStateSyncElement.onServerConnectionStateChange().subscribe((data) => {
  console.log('server connection state change: ', data);
});
```

To unsubscribe from the subscription:

```jsx
subscription?.unsubscribe()
```

The server connection state will be an ENUM with the following states:

```jsx
export enum ServerConnectionState {
  ONLINE = 'online',
  OFFLINE = 'offline',
  PENDING_INIT = 'pendingInit',
  PENDING_DATA = 'pendingData',
}
```

You can also listen to changes in the server connection state using the `useServerConnectionStateChangeHandler()` hook as well:

```jsx
const serverConnectionState = useServerConnectionStateChangeHandler();
```

# 3. Updates to Popover Comments

## Added support for Popover comments using Single Comment Tool

There are now two patterns to add the `Comment Tool` component with [Popover comments](/async-collaboration/comments/setup/popover):

*   (Already Existed) Add a `Comment Tool` next to each element you want to have `Popover` comments
*   (New) Have a single `Comment Tool` and use it to pin a `Popover `comment on a particular element

### Single Comment Tool

If you want to have a single `Comment Tool` in a single location such as the navigation bar, you can do so as well.

To do this, add `data-velt-target-comment-element-id` as an attribute on each element you want to add comments on.

Now, when you click on the `Comment Tool` and click on the target element, it will attach a `Popover` comment to the element.

You will now notice that you can only add one `Comment Annotation` per element.

<Warning>
  If you don't add the `data-velt-target-comment-element-id` attribute, you will be adding multiple `Comment Annotations` on the same element.
</Warning>

```jsx
<div>
  <velt-comment-tool></velt-comment-tool>
  <div class="table">
    <div class="cell" data-velt-target-comment-element-id="cell-id-A" id="cell-id-A">

    </div>
    <div class="cell" data-velt-target-comment-element-id="cell-id-B" id="cell-id-B">

    </div>
  </div>
</div>
```


# null



## Versions

*   Latest SDK: [1.0.96](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.111](https://www.npmjs.com/package/@veltdev/types)

## Notifications Component

The [Notifications](/async-collaboration/notifications/setup) component can be used to notify your users in-app when they receive a reply to a comment or are `@mentioned` by a teammate.

<Info>
  You will need to [enable Notifications in your console](https://console.velt.dev/dashboard/config/notification) in order for Notifications component to work.
</Info>

<Frame>
  <iframe src="https://landing-page-demo-velt.vercel.app/?feature=notifications" allow="camera; microphone" scrolling="no" frameBorder="0" className="w-full" height="700px" />
</Frame>

[Open in larger window](https://landing-page-demo-velt.vercel.app/?feature=notifications)

To implement `Notifications`, simply add it to your app like this:

```jsx React / Next.js
import { VeltNotificationsTool, VeltNotificationsHistoryPanel} from '@veltdev/react';

function YourComponent() {

  return (
    <div className="toolbar">
      <VeltNotificationsTool />
      <VeltNotificationsHistoryPanel />
    </div>
  )
  
}
```

## Custom Notifications

Additionally, you can [send custom notifications](/async-collaboration/notifications/api-add-notification) to this component using our  `https://api.velt.dev/v1/notifications/add` API end point.

Sample Post Request:

```jsx
const options = {method: 'POST', body: JSON.stringify(body)};

fetch('https://api.velt.dev/v1/notifications/add', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
```

Sample Body:

```jsx
{
    "data": {
        "apiKey": "YOUR_API_KEY",
        "authToken": "YOUR_AUTH_TOKEN",
        "documentId": "YOUR_DOCUMENT_ID", 
        "actionUser": {
            "email": "actionuseremail@domain", // required
            "name": "Action Username", // optional
            "photoUrl": "Action User Photo URL", // optional
            "userId": "User ID", // required
        },
        "displayHeadlineMessageTemplate": "This is main template, you can pass variables using curly brackets like this: {actionUser}, {recipientUser}, {yourCustomVariableWithStringValue}",
        "displayHeadlineMessageTemplateData": {
            "actionUser": {
                "email": "actionuseremail@domain", // required
                "name": "Action Username", // optional
                "photoUrl": "Action User Photo URL", // optional
                "userId": "User ID", // required
            },
            "recipientUser": {
                "email": "recipientuseremail@domain", // required
                "name": "Recipient Username", // optional
                "photoUrl": "Recipient User Photo URL", // optional
                "userId": "User ID", // required
            },
            "yourCustomVariableWithStringValue": "Variable will be replaced with this text"
        },
        "displayBodyMessage": "This is body message (Secondary message)",

	 // Pass list of users who should be notified, notification will be shown to all the users in all section in notification panel and notification history panel, but it will be shown in 'forYou' section also to notifyUsers.
        "notifyUsers": [
            {
                "email": "notifyuseremail@domain", // required
                "name": "Notify User Name", // optional
                "photoUrl": "Notify User Photo URL", // optional
                "userId": "User ID", // required
            }
        ]
    }
}
```

## Dark Mode on All Tool and Button Components

You can now configure Dark Mode individually on all Tool and Button Components in the Velt SDK.

Example:

```jsx
<VeltCommentTool darkMode={true} />
<VeltSidebarButton darkMode={true} />
<VeltHuddleTool darkMode={true} />
<VeltRecorderTool darkMode={true} />
<VeltUserInviteTool darkMode={true} />
<VeltArrowTool darkMode={true} />
<VeltNotificationsTool darkMode={true} />
<VeltNotificationsPanel darkMode={true} />
<VeltNotificationsHistoryPanel darkMode={true} />
```

If you want to configure Dark Mode globally, you can also use:

```jsx
client.setDarkMode(true)
```

## Bug Fixes

*   Fixed bug where you could still drag comments into restricted areas
*   Fixed user email related issue for admin users in invite dialog
*   Fixed typed related issues in darkMode
*   Added option to disable live selection with disableFeatures()


# null



## Versions

*   Latest SDK: [1.0.91](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.106](https://www.npmjs.com/package/@veltdev/types)

## Method to return the XPath of the DOM element where a Comment was added.

Introducing the [getElementRefByAnnotationId()](/async-collaboration/comments/customize-behavior/action-methods) method that returns the XPath of the DOM element where the specified comment was added.

```jsx
const commentElement = client.getCommentElement();
let elementRef = commentElement.getElementRefByAnnotationId('annotationId')
```

## Method to scroll the page to a specific Comment

Added the [scrollToCommentByAnnotationId()](/async-collaboration/comments/customize-behavior/action-methods) method that scrolls the page to the specified element where the comment was added. This functionality is contingent upon the presence of the element in the DOM.

```jsx
const commentElement = client.getCommentElement();
commentElement.scrollToCommentByAnnotationId('annotationId')
```

## Live selection style configuration

Added the ability to [customize the styling of Live Selection](/realtime-collaboration/live-selection/customize-behavior) by passing a style object to the `data-live-selection-config` attribute.

```jsx
/**
 * live selection configuration:
 * position:
 * - horizontal: 'left'
 * border:
 * - border: false
 */
<p data-live-selection-enabled="true" 
   data-live-selection-config='{ "horizontal": "left", "border": false }' 
   contenteditable="true">
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolorum, consequatur.
</p>
```

## Event Handler for Click Events on Presence Users

Implemented the [onPresenceUserClick](/realtime-collaboration/presence/customize-behavior) event handler for click events on Presence avatar circles.

```jsx
const onPresenceUserClickEvent = (user) => {
  console.log("Clicked presence user: ", user);
}	

<VeltPresence onPresenceUserClick={(user) => onPresenceUserClickEvent(user)} />
```

## Option to disclude current user from list of Presence Users

The [self](/realtime-collaboration/presence/customize-behavior) property can be used to include or disclude the current user from the list of Presence users. By default the current user is added.

```js
<VeltPresence self={false} />
```

API Method:

```jsx
const presenceElement = client.getPresenceElement();
presenceElement.enableSelf();
presenceElement.disableSelf();
```


# null



## Versions

*   Latest SDK: [1.0.119](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.135](https://www.npmjs.com/package/@veltdev/types)

## Updates to `useLiveState` Hook

The [useLiveState()](https://docs.velt.dev/realtime-collaboration/live-state-sync/setup) Hook was updated to include a config object as a third parameter.

Some background on the `useLiveState()` Hook:

If you are familiar with React's `useState()` hook, we have a similar hook called `useLiveState()`  that can be used to sync data realtime for specific state variables in your code.

Hook syntax:

```jsx
const [value, setValue] = useLiveState(UNIQUE_ID, INITIAL_VALUE, OPTIONS);
```

The hook takes in 3 parameters:

*   `UNIQUE_ID` -> unique id in string to be synced across the screens
*   `INITIAL_VALUE` -> initial value of the state
*   `OPTIONS` (object)
    *   `syncDuration` -> debounce duration in milliseconds to sync realtime (optional, default value 50ms)
    *   `resetLiveState` -> Boolean to reset locatl state value on server side on initiatlize of hook (default: `false`)

The hook returns a setter and getter:

*   `value` -> current state value (similar to useState hook)
*   `setValue` -> function to be called to set next value (similar to useState hook)

Example:

```tsx
import { useLiveState } from "@veltdev/react";

export function MyReactComponent() {
  const [counter, setCounter] = useLiveState < number > ("counter", 0, {
    syncDuration: 100,
    resetLiveState: true
  });

  return (
    <div>
      <button onClick={() => setCounter((counter || 0) - 1)}>-</button>
      <span>Counter: {counter}</span>
      <button onClick={() => setCounter((counter || 0) + 1)}>+</button>
    </div>
  );
}
```

## Option to [Enable DOM Change Detection in Comment Mode](https://docs.velt.dev/async-collaboration/comments/customize-behavior/general-controls)

By default, we skip `Comment` `DOM Change Detection` when users are in `Comment Mode` to improve performance.

However, you can turn `Comment` `DOM Change Detection` back on with the `changeDetectionInCommentMode` property.

This will make `Comment's` reposition themselves if the DOM happens to change while in `Comment Mode`.

`Default: false`

```jsx
<VeltComments changeDetectionInCommentMode={true} />
```

API Methods:

```jsx
const commentElement = client.getCommentElement();
// To enable change detection when comment mode is on
commentElement.enableChangeDetectionInCommentMode();
// To disable change detection when comment mode is on
commentElement.disableChangeDetectionInCommentMode();
```

## Option to [Sort Order of Comments in Sidebar](http://localhost:3000/async-collaboration/comments-sidebar/customize-behavior)

By default, the `Comments` in the `Sidebar` are ordered in descending order of when they were last updated.

You can change this sorting order with the `sort-data` property.

There are three options for sorting:

*   `asc` - to show comments in descendending order of when they were last updated
*   `desc` - to show comments in ascending order of when they were last updated
*   `none` - to show comments in the sequence they were added

```jsx
<VeltCommentsSidebar sortData="asc" />
```


# null



## Versions

*   Latest SDK: [1.0.129](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.146](https://www.npmjs.com/package/@veltdev/types)

## Added Variant support in customization

If you want to have multiple versions of customized components that you can swap between, you can use [variants](/ui-customization/variants).

To define multiple `variants`, add multiple templates of the same component `wireframe` to the `VeltWireframe` component and give them each a `variant` name.

```jsx
<VeltWireframe>
    <VeltCommentsSidebarWireframe variant="sidebar1">
        #Your wireframe for variant sidebar1
    </VeltCommentsSidebarWireframe>

    <VeltCommentsSidebarWireframe variant="sidebar2">
        #Your wireframe for variant sidebar2
    </VeltCommentsSidebarWireframe>
</VeltWireframe>
```

To use a specific variant, define it on the `variant` props when using the Velt component in your app.

```jsx
<div>
    <VeltCommentsSidebar variant="sidebar2"/>
</div>
```

## Added Custom Dropdown Lists

You can have [custom dropdown lists](/async-collaboration/comments/customize-behavior/autocomplete) 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://mintlify.s3-us-west-1.amazonaws.com/velt/images/custom-dropdown.png)

Selecting an item frop the dropdown list will create a `chip` that is placed in the comment text.

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/chip.png)

## Merged useSetLocation and useAddLocation hook

The second parameter of `useSetLocation` can be set to `true` to add additional locations instead of using `useAddLocation`.

```jsx
import { useSetLocation } from "@veltdev/react";

function YourComponent() {

	// to set main location
	useSetLocation(YOUR_LOCATION_OBJECT);
	
	// to set extra location
	useSetLocation(YOUR_EXTRA_LOCATION_OBJECT, true);
}
```

## Option to submit Comment on Enter Key Press

By default, pressing `enter` will add a new line and pressing `shift` + `enter` will submit a comment.

If you want to [change this default behavior](/async-collaboration/comments/customize-behavior/general-controls) so that pressing `enter` will submit a comment, you can set the `enterKeyToSubmit` property to `true`.

```jsx
<VeltComments enterKeyToSubmit={true} />
```

```jsx
// API methods
const commentElement = client.getCommentElement();
// To enable enter key to submit a comment
commentElement.enableEnterKeyToSubmit();
// To disable enter key to submit a comment
commentElement.disableEnterKeyToSubmit();
```

## Added support to disable Shadow DOM on a few more components

There are now a few more components that can have the [Shadow DOM disabled](/ui-customization/customize-css/remove-shadow-dom).

```jsx
<VeltComments
  shadowDom={false}
  dialogShadowDom={false}
  pinShadowDom={false}
  textCommentToolShadowDom={false}
  textCommentToolbarShadowDom={false}
/>


<VeltCommentBubble shadowDom={false} />
<VeltCommentTool shadowDom={false} />
<VeltSidebarButton shadowDom={false} />
<VeltCommentsSidebar shadowDom={false} />
```


# null



## Versions

*   Latest SDK: [1.0.130](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.147](https://www.npmjs.com/package/@veltdev/types)

## Changes to Wireframe Subcomponent Names

### Comment Dialog

`VeltCommentDialogWireframe.ThreadCard.Files` -> `VeltCommentDialogWireframe.ThreadCard.Attachments`

`VeltCommentDialogWireframe.Composer.Files` -> `VeltCommentDialogWireframe.Composer.Attachments`

`VeltCommentDialogWireframe.CommentCount` -> `VeltCommentDialogWireframe.CommentIndex`

### Comments Sidebar

`VeltCommentsSidebarWireframe.PageMode` -> `VeltCommentsSidebarWireframe.PageModeComposer`

### Text Comment Toolbar

`VeltTextCommentToolbarWireframe.Seperator` -> `VeltTextCommentToolbarWireframe.Divider`

### Options Dropdown

`VeltOptionsDropdownContent.MakePrivate.On` -> `VeltOptionsDropdownContent.MakePrivate.Enable`
`VeltOptionsDropdownContent.MakePrivate.Off` -> `VeltOptionsDropdownContent.MakePrivate.Disable`

### Comments Sidebar

`VeltCommentsSidebarWireframe.PageMode` -> `VeltCommentsSidebarWireframe.PageModeComposer`


# null



## Versions

*   Latest SDK: [1.0.133](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.150](https://www.npmjs.com/package/@veltdev/types)

## Added Skeleton loader subcomponent to Comments Sidebar Wireframe

The Comments Sidebar Wireframe now has a [Skeleton loader subcomponent](/ui-customization/features/async/comments/comments-sidebar/overview) that you can modify.

## Added functionality to search by name in @mention dropdown

You can now search by name, in addition to just email, in the `@mention` dropdown

## Added option to show resolved Comments on DOM

By default, resolved Comments are not shown on the DOM.

There is now an option to [show resolved Comments on the DOM](/async-collaboration/comments/customize-behavior/visibility-controls).

```jsx
// Html
<velt-comments resolved-comments-on-dom="true"></velt-comments>

// React
<VeltComments resolvedCommentsOnDom={true} />

// API Methods
const commentElement = client.getCommentElement();
// To show resolved comments on dom
commentElement.showResolvedCommentsOnDom();
// To hide resolved comments on dom
commentElement.hideResolvedCommentsOnDom();
```

## User background color

You can now pass in a color when you identify a user using [client.identify()](/get-started/setup/authenticate)

```jsx
const user = {
    userId: uid,
    name: displayName,
    email: email,
    photoUrl: photoURL,
    color: colorCode, // Hex code value goes in the place of colorCode
    groupId: groupId // this is the organization id the user belongs to.
};

await client.identify(user);
```

## Added additional subcomponents to the Comments Dialog Wireframe

The following subcomponents were added to the Comments Dialog Wireframe:

*   [Priority Dropdown](/ui-customization/features/async/comments/comment-dialog/subcomponents/priority-dropdown)
*   [Status Dropdown](/ui-customization/features/async/comments/comment-dialog/subcomponents/status-dropdown)
*   [Options Dropdown](/ui-customization/features/async/comments/comment-dialog/subcomponents/options-dropdown)
*   [Reaction Tool](/ui-customization/features/async/comments/comment-dialog/subcomponents/reaction-tool)
*   [Reaction Pin](/ui-customization/features/async/comments/comment-dialog/subcomponents/reaction-pin)
*   [Reactions Panel](/ui-customization/features/async/comments/comment-dialog/subcomponents/reactions-panel)
*   [Reactions Pin Tooltip](/ui-customization/features/async/comments/comment-dialog/subcomponents/reaction-pin-tooltip)
*   [Autocomplete Option](/ui-customization/features/async/comments/comment-dialog/subcomponents/autocomplete-option)
*   [Autocomplete Chip Tooltip](/ui-customization/features/async/comments/comment-dialog/subcomponents/autocomplete-chip-tooltip)

## Added support to set custom reactions

You can [set custom reactions](/async-collaboration/comments/customize-behavior/multimedia) 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`, `svg`, or `emoji` field to represent the reaction icon you want to use.

```jsx
const customReactions = {
    "URL_EMOJI_ID": {
        "url": "EMOJI_URL"
    },
    "SVG_EMOJI_ID": {
        "svg": "EMOJI_SVG"
    },
    "TEXT_EMOJI_ID": {
        "emoji": "🤣" // emoji as a text
    }
};

<VeltComments customReactions={customReactions} />
```

API Methods:

```jsx
const commentElement = client.getCommentElement();

const customReactions = {
    "URL_EMOJI_ID": {
        "url": "EMOJI_URL"
    },
    "SVG_EMOJI_ID": {
        "svg": "EMOJI_SVG"
    },
    "TEXT_EMOJI_ID": {
        "emoji": "🤣" // emoji as a text
    }
}
commentElement.setCustomReactions(customReactions);
```

## Changed  type in VeltCommentDialogWireframe.Composer.ActionButton from `file` to `attachments`. Keeping legacy support for `file`.

In the [Comment Dialog Wireframe](/ui-customization/features/async/comments/comment-dialog/overview), we changed the type from `file`  to `attachments`

`<VeltCommentDialogWireframe.Composer.ActionButton type="file" />` ->  `<VeltCommentDialogWireframe.Composer.ActionButton type="attachments" />`

## Added support for customizing attachments in Comment Dialog

The `VeltCommentDialogWireframe.Composer.Attachments` and `VeltCommentDialogWireframe.ThreadCard.Attachments` subcomponents within the [Comment Dialog Wireframe](/ui-customization/features/async/comments/comment-dialog/overview) now support customization.

## Added method listen to Comment Selection changes.

The [onCommentSelectionChange()](/async-collaboration/comments/customize-behavior/event-handlers) method can be used to listen to Comment selection changes.

```jsx
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
const commentElement = client.getCommentElement();
let subscription = commentElement.onCommentSelectionChange().subscribe((data) => {
  console.log('onCommentSelectionChange: ', data);
});
```

To unsubscribe from the subscription:

```jsx
subscription?.unsubscribe()
```

Using Hooks:

The `useCommentSelectionChangeHandler` hook can be used to subscribe to Comment selection changes.

```jsx
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}
        </>
    );
}
```

## Added prop to enable or disable Comment Pin Highlighter

The API Methods already existed, but we added a prop to enable or disable the [Comment Pin Highlighter](/async-collaboration/comments/customize-behavior/ui-controls)

```jsx
<velt-comments comment-pin-highlighter="false"></velt-comments>

// React
<VeltComments commentPinHighlighter={false} />

// API method was already added before, adding here just for refernece purpose
const commentElement = client.getCommentElement();
// To enable comment pin highlighter
commentElement.enableCommentPinHighlighter();
// To disable comment pin highlighter
commentElement.disableCommentPinHighlighter();
```

## Added flag to merge location in `updateLocation` cloud function

You can [update a Location's object fields](/key-concepts/locations/setup/api-update-location) while keeping the location id the same using an api call.

Set the `merge` flag to `true` if you want to merge the new `location` fields into the old `location` fields.

Set the flag to `false` if you want the new `location` object to completely replace the old `location` object.

```jsx
{
    "data": {
        "apiKey": "YOUR_API_KEY",
        "authToken": "YOUR_AUTH_TOKEN",
        "documentId": "YOUR_DOCUMENT_ID",
        "migrate": {
            "oldLocation": YOUR_OLD_LOCATION_OBJECT_HERE,
            "newLocation": YOUR_NEW_LOCATION_OBJECT_HERE
        },
        "merge" : true
    }
}
```


# null



## Versions

*   Latest SDK: [1.0.137](https://www.npmjs.com/package/@veltdev/react)
*   Latest Types: [1.0.157](https://www.npmjs.com/package/@veltdev/types)

## Simplified way to modify wireframe subcomponents

You can now modify subcomponent wireframes using two patterns:

#### a. `Parentless` - Modifying the subcomponent without its parent within the `<VeltWireframe />` component. (recommended)

In this example, we modify the Header subcomponent, which is a subcomponent of the Velt Comment Dialog. In this pattern, we just put the Header subcomponent in the root of `<VeltWireframe />` and modify it. We do not need to add its parent component or any of its siblings.

Example:

```jsx
<VeltWireframe>
    <VeltCommentsSidebarWireframe.Header>
        <div>
            Custom HTML
        </div>
        <VeltCommentsSidebarWireframe.CloseButton/>
        <VeltCommentsSidebarWireframe.Search/>
        <VeltCommentsSidebarWireframe.Status/>
        <VeltCommentsSidebarWireframe.FilterButton/>
    </VeltCommentsSidebarWireframe.Header>
</VeltWireframe>
```

#### a. `With Parent` - Modifying the subcomponent within the context of its parent within the `<VeltWireframe />` component. (not recommended)

In this example, we modify the Header subcomponent, which is a subcomponent of the Velt Comment Dialog component. In this pattern, we include its parent component and siblings. This makes it easier to modify several sibling components at once.

Example:

```jsx
<VeltWireframe>
   <VeltCommentsSidebarWireframe>
        {/* Skeleton */}
        ...
        <VeltCommentsSidebarWireframe.Panel>
            {/* Header */}
            <VeltCommentsSidebarWireframe.Header>
                <div>
                    Custom HTML
                </div>
                <VeltCommentsSidebarWireframe.CloseButton/>
                <VeltCommentsSidebarWireframe.Search/>
                <VeltCommentsSidebarWireframe.Status/>
                <VeltCommentsSidebarWireframe.FilterButton/>
            </VeltCommentsSidebarWireframe.Header>
            {/* Filter */}
            ...
            {/* List */}
            <VeltCommentsSidebarWireframe.List/>
            {/* Empty Placeholder */}
            ...
            {/* Page Mode Composer */}
            ...
        <VeltCommentsSidebarWireframe.Panel/>
    </VeltCommentsSidebarWireframe>
</VeltWireframe>
```

<Note> If you modify the component in both the `Parentless` and `With Parent` pattern, the `With Parent` pattern will override the `Parentless` pattern. </Note>

## Detect if Velt SDK is initialized

[To detect if the Velt SDK is initialized](/get-started/setup/advanced), subscribe using the following method:

```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]);
}

```


# null



# 3.0.56

### Improvements

*   \[**Comments**]: Improved the system grouping logic for locations.
*   \[**Comments**]: Enhanced `updateContext` logic to prevent unnecessary updates if the passed context object remains unchanged.
*   \[**Comments**]: Exposed `commentAnnotations` variable in the comments sidebar so that it can be used in `Velt Data` and `Velt If` Components.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where adding the `Copy Link` wireframe component in the header options menu generated undefined Comment URLs.


# null



# 3.0.63

### Bug Fixes

*   \[**Comments**]: Fixed issue where bottom sheet was incorrectly opening in the sidebar on mobile devices.

# 3.0.62

### Features

*   \[**Comments**]: Fixed issue where edit comment composer was not appearing in the sidebar.

*   \[**Comments**]: Added offset property to Comment Player Timeline. This allows comment bubbles to be positioned relative to both parent and child video clips.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentPlayerTimeline offset={10} />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comment-player-timeline offset="10"></velt-comment-player-timeline>
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Dynamic Hooks**]: Now the LiveStateSync and Views hooks support dynamic input parameters for non-primitive data types.

### Bug Fixes

*   \[**Comments**]: Fixed issue where edit comment composer was not appearing in the sidebar.


# null



# 3.0.64

### Bug Fixes

*   \[**Comments**]: Fixed an issue where `onCommentSidebarData` event was getting triggered multiple times on sidebar clicks.
*   \[**Comments**]: Fixed an issue where empty placeholder was not being displayed in the sidebar for page mode and custom action filters.


# null



# 3.0.65

### Improvements

*   \[**Comments**]: Added support for light mode in the contact chip tooltip.
*   \[**Comments**]: Removed unnecessary filtering in the sidebar when comment annotation selection changes.


# null



# 3.0.66

### Features

*   \[**Comments**]: Added support for passing Comment Annotation objects to Standalone Comment Thread component.

    *   When using annotations from other documents:
        *   Comments will be read-only
        *   Reactions and recordings will not be rendered
    *   This enables creating Kanban boards by fetching comment annotations from multiple documents using our REST APIs.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentThread annotation={COMMENT_ANNOTATION_OBJECT} />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comment-thread annotation="STRINGIFIED_COMMENT_ANNOTATION_OBJECT"></velt-comment-thread>
        ```
      </Tab>
    </Tabs>

*   \[**Comments**]: Added `shortUserName` feature to control display of user names.

    *   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.
    *   It's enabled by default.

    <Tabs>
      <Tab title="React / Next.js">
        **Using Props:**

        ```jsx
        <VeltComments shortUserName={false} />
        ```

        **Using API:**

        ```js
        const commentElement = client.getCommentElement();
        commentElement.enableShortUserName();
        commentElement.disableShortUserName();
        ```
      </Tab>

      <Tab title="Other Frameworks">
        **Using Props:**

        ```html
        <velt-comments short-user-name="false"></velt-comments>
        ```

        **Using API:**

        ```js
        const commentElement = Velt.getCommentElement();
        commentElement.enableShortUserName();
        commentElement.disableShortUserName();
        ```
      </Tab>
    </Tabs>


# null



# 3.0.67

### Features

*   \[**UI Customization**]: Introducing Themes! Now you can customize the look and feel of Velt components using CSS variables. This enables you to match Velt's UI with your application's design system.

    *   The following components now support theming (others will be added soon):
        *   Comment Components
        *   Recording Components
        *   Reactions

    *   You can customize:
        *   Border radius
        *   Spacing
        *   Typography
        *   Colors for light and dark modes
            *   Base Colors
            *   Accent Colors
            *   Text Shades
            *   Background Shades
            *   Border Shades
            *   Status Colors (error, warning, success)
            *   Transparent colors

    *   Learn more about UI Customization [here](/ui-customization/overview).

<Tabs>
  <Tab title="Border Radius">
    ```css
    --velt-border-radius-2xs: 0.125rem; // 2px
    --velt-border-radius-xs: 0.25rem; // 4px
    --velt-border-radius-sm: 0.5rem; // 8px
    --velt-border-radius-md: 0.75rem; // 12px
    --velt-border-radius-lg: 1rem; // 16px
    --velt-border-radius-xl: 1.25rem; // 20px
    --velt-border-radius-2xl: 1.5rem; // 24px
    --velt-border-radius-3xl: 2rem; // 32px
    --velt-border-radius-full: 5rem; // 80px
    ```
  </Tab>

  <Tab title="Spacing">
    ```css
      --velt-spacing-2xs: 0.125rem; // 2px
      --velt-spacing-xs: 0.25rem; // 4px
      --velt-spacing-sm: 0.5rem; // 8px
      --velt-spacing-md: 0.75rem; // 12px
      --velt-spacing-lg: 1rem; // 16px
      --velt-spacing-xl: 1.25rem; // 20px
      --velt-spacing-2xl: 1.5rem; // 24px
    ```
  </Tab>

  <Tab title="Typography">
    ```css
      --velt-default-font-family: sans-serif;
      --velt-font-size-2xs: 0.625rem; // 10px
      --velt-font-size-xs: 0.75rem; // 12px
      --velt-font-size-sm: 0.875rem; // 14px
      --velt-font-size-md: 1rem; // 16px
      --velt-font-size-lg: 1.5rem; // 24px
      --velt-font-size-xl: 1.75rem; // 28px
      --velt-font-size-2xl: 2rem; // 32px
    ```
  </Tab>

  <Tab title="Colors - Light Mode">
    ```css
      /* Base Colors */
      --velt-light-mode-green: #0DCF82;
      --velt-light-mode-magenta: #A259FE;
      --velt-light-mode-amber: #FF7162;
      --velt-light-mode-purple: #625DF5;
      --velt-light-mode-cyan: #4BC9F0;
      --velt-light-mode-orange: #FE965C;
      --velt-light-mode-black: #080808;
      --velt-light-mode-white: #FFFFFF;
      --velt-light-mode-gray: #EBEBEB;

      /* Accent Colors */
      --velt-light-mode-accent: #625DF5;
      --velt-light-mode-accent-text: #9491F8;
      --velt-light-mode-accent-hover: #534FCF;
      --velt-light-mode-accent-foreground: #FFFFFF;
      --velt-light-mode-accent-light: #F2F2FE;
      --velt-light-mode-accent-transparent: rgba(148, 145, 248, 0.08);

      /* Text Shades */
      --velt-light-mode-text-0: #0A0A0A;
      --velt-light-mode-text-1: #141414;
      --velt-light-mode-text-2: #1F1F1F;
      --velt-light-mode-text-3: #292929;
      --velt-light-mode-text-4: #3D3D3D;
      --velt-light-mode-text-5: #525252;
      --velt-light-mode-text-6: #666666;
      --velt-light-mode-text-7: #7A7A7A;
      --velt-light-mode-text-8: #858585;
      --velt-light-mode-text-9: #999999;
      --velt-light-mode-text-10: #B8B8B8;
      --velt-light-mode-text-11: #A3A3A3;
      --velt-light-mode-text-12: #8F8F8F;

      /* Background Shades */
      --velt-light-mode-background-0: #FFFFFF;
      --velt-light-mode-background-1: #FAFAFA;
      --velt-light-mode-background-2: #F5F5F5;
      --velt-light-mode-background-3: #F0F0F0;
      --velt-light-mode-background-4: #EBEBEB;
      --velt-light-mode-background-5: #E5E5E5;
      --velt-light-mode-background-6: #E0E0E0;
      --velt-light-mode-background-7: #DBDBDB;
      --velt-light-mode-background-8: #D6D6D6;
      --velt-light-mode-background-9: #D1D1D1;
      --velt-light-mode-background-10: #CCCCCC;

      /* Border Shades */
      --velt-light-mode-border-0: #FFFFFF;
      --velt-light-mode-border-1: #FAFAFA;
      --velt-light-mode-border-2: #F5F5F5;
      --velt-light-mode-border-3: #F0F0F0;
      --velt-light-mode-border-4: #EBEBEB;
      --velt-light-mode-border-5: #E5E5E5;
      --velt-light-mode-border-6: #E0E0E0;
      --velt-light-mode-border-7: #DBDBDB;
      --velt-light-mode-border-8: #D6D6D6;
      --velt-light-mode-border-9: #D1D1D1;
      --velt-light-mode-border-10: #CCCCCC;

      /* Status Colors */
      /* Error */
      --velt-light-mode-error: #FF7162;
      --velt-light-mode-error-hover: #DE5041;
      --velt-light-mode-error-foreground: #FFFFFF;
      --velt-light-mode-error-light: #FFF4F2;
      --velt-light-mode-error-transparent: rgba(255, 113, 98, 0.08);

      /* Warning */
      --velt-light-mode-warning: #FFCD2E;
      --velt-light-mode-warning-hover: #C69400;
      --velt-light-mode-warning-foreground: #474747;
      --velt-light-mode-warning-light: #FFFBEE;
      --velt-light-mode-warning-transparent: rgba(255, 205, 46, 0.08);

      /* Success */
      --velt-light-mode-success: #198F65;
      --velt-light-mode-success-hover: #006B41;
      --velt-light-mode-success-foreground: #FFFFFF;
      --velt-light-mode-success-light: #EDF6F3;
      --velt-light-mode-success-transparent: rgba(25, 143, 101, 0.08);

      /* Transparent Colors */
      --velt-light-mode-background-transparent: rgba(255, 255, 255, 0.80);
      --velt-light-mode-border-transparent: rgba(0, 0, 0, 0.16);
      --velt-light-mode-animation-transparent: rgba(255, 255, 255, 0.2);
    ```
  </Tab>

  <Tab title="Colors - Dark Mode">
    ```css
      /* Base Colors */
      --velt-dark-mode-green: #0DCF82;
      --velt-dark-mode-magenta: #A259FE;
      --velt-dark-mode-amber: #FF7162;
      --velt-dark-mode-purple: #625DF5;
      --velt-dark-mode-cyan: #4BC9F0;
      --velt-dark-mode-orange: #FE965C;
      --velt-dark-mode-black: #080808;
      --velt-dark-mode-white: #FFFFFF;
      --velt-dark-mode-gray: #EBEBEB;

      /* Accent Colors */
      --velt-dark-mode-accent: #625DF5;
      --velt-dark-mode-accent-text: #9491F8;
      --velt-dark-mode-accent-hover: #534FCF;
      --velt-dark-mode-accent-foreground: #FFFFFF;
      --velt-dark-mode-accent-light: #F2F2FE;
      --velt-dark-mode-accent-transparent: rgba(148, 145, 248, 0.08);

      /* Text Shades */
      --velt-dark-mode-text-0: #FFFFFF;
      --velt-dark-mode-text-1: #F5F5F5;
      --velt-dark-mode-text-2: #EBEBEB;
      --velt-dark-mode-text-3: #E0E0E0;
      --velt-dark-mode-text-4: #D6D6D6;
      --velt-dark-mode-text-5: #C2C2C2;
      --velt-dark-mode-text-6: #ADADAD;
      --velt-dark-mode-text-7: #8F8F8F;
      --velt-dark-mode-text-8: #7A7A7A;
      --velt-dark-mode-text-9: #666666;
      --velt-dark-mode-text-10: #525252;
      --velt-dark-mode-text-11: #474747;
      --velt-dark-mode-text-12: #3D3D3D;

      /* Background Shades */
      --velt-dark-mode-background-0: #0F0F0F;
      --velt-dark-mode-background-1: #1A1A1A;
      --velt-dark-mode-background-2: #1F1F1F;
      --velt-dark-mode-background-3: #242424;
      --velt-dark-mode-background-4: #292929;
      --velt-dark-mode-background-5: #2E2E2E;
      --velt-dark-mode-background-6: #333333;
      --velt-dark-mode-background-7: #383838;
      --velt-dark-mode-background-8: #3D3D3D;
      --velt-dark-mode-background-9: #424242;
      --velt-dark-mode-background-10: #474747;

      /* Border Shades */
      --velt-dark-mode-border-0: #0F0F0F;
      --velt-dark-mode-border-1: #1A1A1A;
      --velt-dark-mode-border-2: #1F1F1F;
      --velt-dark-mode-border-3: #242424;
      --velt-dark-mode-border-4: #292929;
      --velt-dark-mode-border-5: #2E2E2E;
      --velt-dark-mode-border-6: #333333;
      --velt-dark-mode-border-7: #383838;
      --velt-dark-mode-border-8: #3D3D3D;
      --velt-dark-mode-border-9: #424242;
      --velt-dark-mode-border-10: #474747;

      /* Status Colors */
      /* Error */
      --velt-dark-mode-error: #FF7162;
      --velt-dark-mode-error-hover: #DE5041;
      --velt-dark-mode-error-foreground: #FFFFFF;
      --velt-dark-mode-error-light: #FFF4F2;
      --velt-dark-mode-error-transparent: rgba(255, 113, 98, 0.08);

      /* Warning */
      --velt-dark-mode-warning: #FFCD2E;
      --velt-dark-mode-warning-hover: #C69400;
      --velt-dark-mode-warning-foreground: #474747;
      --velt-dark-mode-warning-light: #FFFBEE;
      --velt-dark-mode-warning-transparent: rgba(255, 205, 46, 0.08);

      /* Success */
      --velt-dark-mode-success: #198F65;
      --velt-dark-mode-success-hover: #006B41;
      --velt-dark-mode-success-foreground: #FFFFFF;
      --velt-dark-mode-success-light: #EDF6F3;
      --velt-dark-mode-success-transparent: rgba(25, 143, 101, 0.08);

      /* Transparent Colors */
      --velt-dark-mode-background-transparent: rgba(0, 0, 0, 0.80);
      --velt-dark-mode-border-transparent: rgba(255, 255, 255, 0.16);
      --velt-dark-mode-animation-transparent: rgba(255, 255, 255, 0.2);
    ```
  </Tab>
</Tabs>

*   Example of theme customisation:
    *   You can update the following variables in `<body>` tag to change the theme.
    *   For testing, try copy pasting the following sample themes in body tag:
    ```css
    body {
      --velt-light-mode-accent: #0BA528;
      --velt-light-mode-accent-text: #0BA528;
      --velt-light-mode-accent-hover: #08841F;
      --velt-light-mode-accent-foreground: #FFFFFF;
      --velt-light-mode-accent-light: #DFF9E4;
      --velt-light-mode-accent-transparent: rgba(11, 165, 40, 0.08);

      --velt-dark-mode-accent: #0BA528;
      --velt-dark-mode-accent-text: #0BA528;
      --velt-dark-mode-accent-hover: #08841F;
      --velt-dark-mode-accent-foreground: #FFFFFF;
      --velt-dark-mode-accent-light: #DFF9E4;
      --velt-dark-mode-accent-transparent: rgba(11, 165, 40, 0.08);

      --velt-border-radius-2xs: 2px;
      --velt-border-radius-xs: 2px;
      --velt-border-radius-sm: 2px;
      --velt-border-radius-md: 2px;
      --velt-border-radius-lg: 2px;
      --velt-border-radius-xl: 2px;
      --velt-border-radius-2xl: 2px;
      --velt-border-radius-3xl: 2px;
      --velt-border-radius-full: 2px;
    }
    ```


# null



# 3.0.57

### Bug Fixes

*   \[**Notifications**]: Optimized and fixed issues related to loading notifications on `documentId` and `organizationId` change.


# null



# 3.0.58

### Improvements

*   \[**Comments**]: Added ability to sort inline comments:

    *   `asc`: Show comments in ascending order of last updated timestamp
    *   `desc`: Show comments in descending order of last updated timestamp
    *   `none`: Show comments in order of creation (default)

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltInlineCommentsSection sortData="desc" />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-inline-comments-section sort-data="asc"></velt-inline-comments-section> 
        ```
      </Tab>
    </Tabs>

*   \[**Comments**]: Further improved how empty comments are handled:
    *   Empty comments are now hidden from the sidebar and sidebar button count
    *   In popover mode, clicking a new comment button discards any previous empty comment

*   \[**Comments**]: Added delete option for each comment in annotations when user has admin privileges


# null



# 3.0.59

### Bug Fixes

*   \[**Comments**]: Fixed several issues with the comment dialog and inline comments:
    *   Fixed cursor position not being set correctly when focusing comment input
    *   Fixed an issue where editing a comment and saving it as a draft created a new comment
    *   Fixed an issue where sometimes comment pin was visible on the inline comments section


# null



# 3.0.61

### Features

*   \[**REST APIs**]: Added advanced queries and pagination for GET endpoints.
    *   You need to upgrade to version 3.0.61 and enable this in your developer console.
    *   Check out the [V2 REST APIs endpoints](/api-reference/rest-apis/comments-feature/comment-annotations/get-comment-annotations-v2) for more information.

# 3.0.60

### Features

*   \[**Comments**]: Added ability to enable/disable recording transcription feature on recorder:

    <Tabs>
      <Tab title="React / Next.js">
        **Using Props:**

        ```jsx
        <VeltComments recordingTranscription={false} />
        ```

        **Using API Methods:**

        ```javascript
        // Using comment element
        const commentElement = client.getCommentElement();
        commentElement.enableRecordingTranscription();
        commentElement.disableRecordingTranscription();

        // Or using recorder element 
        const recorderElement = client.getRecorderElement();
        recorderElement.enableRecordingTranscription();
        recorderElement.disableRecordingTranscription();
        ```
      </Tab>

      <Tab title="Other Frameworks">
        **Using Props:**

        ```html
        <velt-comments recording-transcription="false"></velt-comments>
        ```

        **Using API Methods:**

        ```javascript
        // Using comment element
        const commentElement = Velt.getCommentElement();
        commentElement.enableRecordingTranscription();
        commentElement.disableRecordingTranscription();

        // Or using recorder element 
        const recorderElement = Velt.getRecorderElement();
        recorderElement.enableRecordingTranscription();
        recorderElement.disableRecordingTranscription();
        ```
      </Tab>
    </Tabs>

### Bug Fixes

*   \[**Comments**]: Fixed range error that occurred when recording without comment text


# null



# 3.0.27

### New Features

*   \[**Comments**]: Added a prop to enable confirmation before deleting a reply.

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltComments deleteReplyConfirmation={true} />
    ```

    Using API:

    ```javascript
    const commentElement = client.getCommentElement();
    commentElement.enableDeleteReplyConfirmation();
    commentElement.disableDeleteReplyConfirmation();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-comments delete-reply-confirmation="true"></velt-comments>
    ```

    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.enableDeleteReplyConfirmation();
    commentElement.disableDeleteReplyConfirmation();
    ```
  </Tab>
</Tabs>

*   \[**Comments**]: Added a callback method for when a comment link is copied. You can use this to track when a comment link is copied or show a confirmation toast.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    Using Hooks:

    ```jsx
      const commentLink = useCommentCopyLinkHandler();
      useEffect(() => {
        console.log('commentLink', commentLink);
      }, [commentLink]);
    ```

    Using API:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.onCopyLink().subscribe((commentLink) => {
      console.log(commentLink);
    });
    ```
  </Tab>

  <Tab title="React / Next.js">
    Using API:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.onCopyLink().subscribe((commentLink) => {
      console.log(commentLink);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.onCopyLink().subscribe((commentLink) => {
      console.log(commentLink);
    });
    ```
  </Tab>
</Tabs>

*   \[**Comments**]: Added a minimal Actions Dropdown in Multithread comment dialog. It contains actions like 'Mark all as read', 'Mark all as resolved'.

### Improvements

*   \[**UI Customization**]: Renamed the `velt data` prop to `field` (old: `path`) to improve readability. This is backward compatible.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltData field='userContact.name' />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-data field="userContact.name"></velt-data>
    ```
  </Tab>
</Tabs>


# null



# 3.0.40

### Bug Fixes

*   \[**Mentions**]: Resolved an issue where `atHereDescription` was not rendering for non-organization users.

# 3.0.39

### New Features

*   \[**Notifications**]: Added API to mark a single notification as read by notificationId.

    <Tabs>
      <Tab title="React / Next.js">
        ```javascript
        const notificationElement = client.getNotificationElement();
        notificationElement.markNotificationAsReadById("notificationId");
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```javascript
        const notificationElement = Velt.getNotificationElement();
        notificationElement.markNotificationAsReadById("notificationId");
        ```
      </Tab>
    </Tabs>

*   \[**Debugger**]: Added call to `setDocument` method to the debugger.

### Improvements

*   \[**Mentions**]: Added `atHereDescription` to the `description` field of the @mention data object.

### Bug Fixes

*   \[**Notifications**]: Fixed an issue where the "For You" tab was not displaying the updated document name on initial load.

# 3.0.38

### New Features

*   \[**Mentions**]: Added styling for @mention in the composer when adding or editing a comment.

### Improvements

*   \[**React Hooks**]: Updated client and comment related hooks to support dynamic input values.

### Bug Fixes

*   \[**Mentions**]: Fixed an issue in the `updateContactList` API where the passed contact list data was being mutated directly.
*   \[**Mentions**]: Resolved an issue where @mentions with special characters were not working correctly.


# null



# 3.0.42

### New Features

*   \[**Live Selection**]: Added new configurations to customize the UI and behavior of the live selection feature:
    *   Enable/disable user indicator
    *   Set user indicator position
    *   Set user indicator type
    *   Enable/disable default elements tracking
    *   Enable/disable default styling
    *   Earlier the live selection was triggered on click, now it is triggered on keyboard actions as well.
    *   [Learn more](/realtime-collaboration/live-selection/customize-behavior).

# 3.0.41

### New Features

*   \[**Comments**]: Added ability to apply custom filtering, sorting and grouping in comments sidebar.
    *   Here is the overview on how it works:
        *   Enable custom actions in the comments sidebar.
        *   Add action buttons to the sidebar wireframe.
        *   Implement callback and event handlers to handle custom filtering, sorting, and grouping logic.
        *   Set custom filtered data in the comments sidebar.
    *   [Learn more](/async-collaboration/comments-sidebar/customize-behavior#2-custom-filtering-sorting-and-grouping).


# null



# 3.0.44

### Improvements

*   \[**Comments**]: Added "This page" label to the sidebar filters.
*   \[**Comments**]: Added React wireframe component for Navigation button:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentDialogWireframe.NavigationButton />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-dialog-navigation-button-wireframe></velt-comment-dialog-navigation-button-wireframe>
    ```
  </Tab>
</Tabs>

# 3.0.43

### New Features

*   \[**Comments**]: Added "focused thread mode" in the comments sidebar:
    *   In this mode, when you click on a comment in the sidebar, it will open the thread in expanded view within the sidebar itself.
    *   Other threads and actions like filters, search etc are hidden behind a back button.
    *   Turning this on also adds a navigation button in the comment dialog. Clicking it will navigate to the comment and also trigger a callback.
    *   If you had previously used a wireframe for the comment dialog, you will need to add the [navigation button wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/navigation-button) and the [focused thread wireframe](/ui-customization/features/async/comments/comments-sidebar/subcomponents/focused-thread).

        <Tabs>
          <Tab title="React / Next.js">
            ```jsx
            <VeltCommentsSidebar focusedThreadMode={true} />
            ```

            **Handling the navigation button click:**

            ```jsx
            <VeltCommentsSidebar onCommentNavigationButtonClick={onCommentNavigationButtonClick} />

              // event handler for when a comment is clicked on 
              const onCommentNavigationButtonClick = (event) => {
                console.log('onCommentNavigationButtonClick', event);
                //handle custom navigation by getting location if you have used Locations
                const { pageId } = event.location;
                //handle custom navigation by getting context if you have used addContext()
                const { pageId } = event.context;
                yourNavigateToPageMethod(pageId);
              };
            ```
          </Tab>

          <Tab title="Other Frameworks">
            ```html
            <velt-comments-sidebar focused-thread-mode="true"></velt-comments-sidebar>
            ```

            **Handling the navigation button click:**

            ```javascript
            const commentSidebarElement = document.querySelector('velt-comments-sidebar');
            commentSidebarElement.addEventListener('onCommentNavigationButtonClick', (s) => {
              console.log('onCommentNavigationButtonClick', s.detail);
            });
            ```
          </Tab>
        </Tabs>

*   \[**Comments**]: Added standalone thread wireframe component:
    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltWireframe>
          <VeltCommentThreadWireframe>
            {/* Velt Comment Dialog Wireframe */}
          </VeltCommentThreadWireframe>
        </VeltWireframe>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-wireframe style="display: none;">
          <velt-comment-thread-wireframe>
            <!-- Velt Comment Dialog Wireframe -->
          </velt-comment-thread-wireframe>
        </velt-wireframe>
        ```
      </Tab>
    </Tabs>

*   \[**Live Selection**]: Add ability to get live selection data for the document:
    <Tabs>
      <Tab title="React / Next.js">
        **Using Hook:**

        ```jsx
          const liveSelectionData = useLiveSelectionDataHandler();

          useEffect(() => {
            console.log('liveSelectionData', liveSelectionData);
          }, [liveSelectionData]);
        ```

        **Using API:**

        ```javascript
          const selectionElement = client.getSelectionElement();
          selectionElement.getLiveSelectionData().subscribe((liveSelectionData: LiveSelectionData) => {
            console.log("liveSelectionData: ", liveSelectionData);
          });
        ```
      </Tab>

      <Tab title="Other Frameworks">
        **Using API:**

        ```javascript
          const selectionElement = Velt.getSelectionElement();
          selectionElement.getLiveSelectionData().subscribe((liveSelectionData: LiveSelectionData) => {
            console.log("liveSelectionData: ", liveSelectionData);
          });
        ```
      </Tab>
    </Tabs>

*   \[**Comments**]: Added standalone `Velt Comment Text` component:

    *   When you put any text inside this component and provide an annotationId, it will automatically highlight the text and attach the comment to it.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentText multiThreadAnnotationId='MULTI_THREAD_ANNOTATION_ID'>
          {/* your content here */}
        </VeltCommentText>

        <VeltCommentText annotationId='ANNOTATION_ID'>
          {/* your content here */}
        </VeltCommentText>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comment-text multi-thread-annotation-id="MULTI_THREAD_ANNOTATION_ID">
          <!-- your content here -->
        </velt-comment-text>

        <velt-comment-text annotation-id="ANNOTATION_ID">
          <!-- your content here -->
        </velt-comment-text>
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Notifications**]: Changed the default maximum days for which Notifications should be displayed from 30 days to 15 days.
*   \[**Notifications**]: Added complete document and organization metadata objects to the Notification metadata object.


# null



# 3.0.45

### New Features

*   \[**Comments**]: Added config to restrict resolve action to admin users only:
    <Tabs>
      <Tab title="React / Next.js">
        **Using props:**

        ```jsx
        <VeltComments resolveStatusAccessAdminOnly={true} />
        ```

        **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();
        ```
      </Tab>

      <Tab title="Other Frameworks">
        **Using props:**

        ```html
        <velt-comments resolve-status-access-admin-only="true"></velt-comments>
        ```

        **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();
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Comments**]: Added ability to @mention emails not present in the contact list.
*   \[**Comments**]: Implemented focus on composer when clicked anywhere within the composer.


# null



# 3.0.47

### New Features

*   \[**Webhooks**]: Added configuration option to encrypt webhook payloads using a secret key.
    *   Configure this option in the [Velt Console](https://console.velt.dev/dashboard/config/webhook).
    *   Encryption details:
        *   Payload encryption: AES-256-CBC
        *   Key encryption: RSA with PKCS1 OAEP padding and SHA-256 hash
    *   Public key format:
        *   Provide only the base64-encoded key string, without PEM headers/footers
        *   Recommended key size: 2048 bits
    *   Example of setting up encryption for Node.js:

<Tabs>
  <Tab title="Sample Encrypted Payload">
    ```js
    {
      "encryptedData": "1rtsa9UVvXzkP+u0ax2TOlz6xKcwKXhmtHyQF1I4II8X4n9uYb944Q/6AfUNFc2zQj9+AWJIV1Gtoo0j+j5VI8qS4kCVnP4In6v0I3wVECldgZsNAwwD4wKp85OJZUJL4scQmJJK+XXmMNGOW094BcIIa6zKRqYKja5RBm5zEj3k1qsP3WZkUXpggJ4FNuHkWX2nkoDLP5Rby6CY186TEeBIxY+aKS6FyWmOiDDC6ZfuY++BFNJbksNvsbBogDqHB2qa30nK9oEcOKSsXdU4AYof/mPOG01fK2diK3vyk4qcL83mJ0cXm7+SbM+FBFeJpdR+A7iIez1XrdnGlAqppnSfDoNBv2WZ/lRyZJWOyW7QHySMNTn746+JDr8oltIBDVUx5c2m8A/YeQ6E3wWEjjRZcfz3GNSzpEx+jqeNxS0StN7BUXUyHt3786EaXiUtjb2OtrP56mlidXytdHhPZPOy7stRwHnwgXfm5aLsS2yJSs3gSSUubL+ka4fhaJsqxtgXQATSh0RtNXSmAbx930DKn2DipbP23fJRduju/GP1nHnKuy8bOuyB5Du//RrysvKVC4+lMd4mVIc7cSXe25qcPjJFZGpJtJdkNwOZoWCmxMSdR32HBgo7KWJeOWqnWyuLdjQOaxol+JtTu8lopeQk7qfncEXMLcT7YRVQ4t1LZ5T9o4pZEtaOg1LwyX58VQS1OHvgBFWlEPxLfdS1r4c1YzMXLNA4sfYEp06Z11IlEFVCtWobK5//tLc+sIpwfMzdJ3VtVl9Z2XB9kASlnHf88eOdtzvn5A0CRhVBY/v855CttAy/WlPINtXxXSxm9oVMjrBFueWAZ3LQiXDl25to62L5i0NR93zEBKj1BG8egy3F27o8s5kcvrwpc3NGrmDe7x3S11noDAFsxZRWpHnRIapHcsrLWOjWVEumvUxlApKGKL3Ax80XBoN+aTNG4SXGq3dRHSneIs/MNSb0BGWoOD5U5ow58R1tvpzJHtLLnmesL1Vhr23Cug8KHU2q7+e8AnGGPTJIRKfVXjocMDclhDAk5/nuvtUTYG/hRZEQ1yCx3T7H08I6GvyOv4ErtKr+r883hXSYzf1K9eqk7de5mnmxwSEiAh0zagvZ+lMYhWpayeo+xHvtoyzfTsLNyXKc6AYZxfoIVK6UuBfkDnXiAh+NuJDa3wKwig13gQX8GmdJXeSSatI6uuXI1IU5xKIXysaHeAOaHfni+cfDgvUZTtVbWc1qDcNOVEUSl9KsjOUUgdzvST1tJ1ezMNZFbhlrPB3t5y0XvM9QQh1GyyeABxHl8nH/Icrp2Shf5vBntNbRZ3PlzK7nVtgTxXaKhZnGobwY7uruPpahNfkEi83JvOOnHeHBMXrVMAr8GHDRi8099wzvJRHYcb2p6eWocQsDV1X6tcTLuxj3EHGwykWREkkTDQ5C/F40n97PP0U2cxSGJIMePUwgAYw5OFo0dJMsU1HvXjm+2JoO8DkdwPl3Bc9F22trvsA3QecUCKQDGMTuFrFxtlubtJYtVl7w3pBST0SCKx3G2QiycRz0FMWv2FJpazQl6jE4xEqeKf7fiUn/QIo4Levk745LPhfr2tzlXbkdZ2q9TtmSAs5hjpK7ndswbIbvV8Ju5V8mDJXSR0y0NKG2C/8/vTB0xfqYtW/Bv3cXj6do9UQzP6fOFC4SGvYh/l8yohJmCTFq0tETqvZr9Atw9ZOz2cIBFx76wlS/eR9iB/JZ3DGM+2THC6Mjv70ipWX32UW7620Bb5KONm3Vw0eeIHckUn6QaHGfFL/URT6mr7YCJhG5lZynWYZcLv/ffWuFcSmO9p0xCrwqqPEjdaaGs52mqmA4Ikt9MulKAEp6p65V1vxt7Tdy6m9UVjzbEy1zFuU9iOHBAAaj6A8Mj1EEUe6sNx3fLHnC2c0+2Zf3eUxMZPm5dQZPOUXLI28yoCliBIhTYTSh7ATULDDvcnNMs/ziuG7WT/U1wuIHkT5kEE73tnG1EZY4RDODbQobmpBegcuUEh64HEGS7+aK/KPYWxFxWW5oVd0Dc7kvpariXqEhlNdDY65b2T8uBw8bI/HrfvT8d0EnsPz26B1xKZYqyusWnlR+10KdYzPNoupx8vWk74PW8zI5qlcV497SPtvn12a3wvZ8adJzMuP4hsBoKHG/M2nf0lOMbo1gcbHbT0FqcHE3mixY3lU+UnNC5jpmNCs1tK8yqeQdVtHE3YM4Y5SsnBTJddUWVpUxZ6rlU+H2NW/uGcDLBs3HmERTn1l6E1mmqKB2kPA/+Y/YbILXNojbkgRE/3lki5kX4+pjHDxF/mWEEeXpjIl4yKG97mVS2J0dGoJ5CqLv6/CdHhtwu35UydBVDVGHywufVLwPgEiDA9RklM/bQw3ojdlTrn6+irDcz8/Tj7KmK2votLaN6yIEM8Ex2htyBlyX/47eEsh63nSNwSx+uPcTxjH9N5cJpWzJ2KcBMIqZsWOTgISBUndgRdoVTFySY2XwbHlDjh8RCLLBsYRhvOK+nvNqEBnrfzz81B/sqDO1whQDTKT3ZcFnZouaVImRGHcOt0sRioq/JGHAHzRjyc/V9Gb/zTlI8QQob5y5k7dfReAy1rGdkeIa3LXSwWGz8hDjEnGsGGIC4evdiefgoJHkhzEywi/QUEOOnqms/0BzexbLP+89qMgGMlEbA9iLAW/BZgsAkxm+NHqGNtz9HDJStpqewElgjMQ+wV3TUGbrmY0O/FyQn/CXyhXjdRC0/5S1tZnzBMyolHF2a5L5EAzGck2MuV7TgLs6LcvGm7kIeq0vmBCkiUB4IBHMhraU7Ba+cC+CW7tDK0Tkanri5KSMXSXamJpU869Jcsk1JLm69ATMl3eIb5rPx5+GbPUrRogEUP3HQeLMQP8jjq6fVwzGPQByF70t0fE+Z23NuCLzhVss0YkMmzcKK8GjKCJ0vnCA0qanxovpDgCOHjgxvy44N+QNWfUynIKVHS9m7FDE3RgKf7rOfSM9vJ7F/KWo7kywi36ajuFbWcON/MTvlpPUhGm5dboiz3vyfpTWkQbd9XX7SPVBWCkvGg+A87R7RSN8bsWbmYm5m2wt3jrkBVSDn5FV3rek6X0GSpTDTWJ9ktmjKtshplXn7fx7XAKtS4hpEMGhZwi/LWvfTsGqOJlqi2FwYPLI7SVunch2VSfssejrfwxJHPqF50wTv6ax28lp7wToqsVunZprdhyY++gds/LAz083dZLM3EYcbHuGVXiNRFxptpiQNjEnyjZX0fc8UF1W2icDt7Gd5Pp2ckaPERLE+tJ+ackMxomH2/HjFB3XRXlDCoKuljtJ2cbw/gVPmHtV7Qw2w6tWaCzYP3g1D47BlrIqBV4RWjcPRjthfcWPnwUSSHwlJ4dLMQ+cJ402ol+HUukAKpkh5lcjME0uaD8KKReD/Ee9r4kubIR7z9JViXjnJJl3Jxr6KtK3abrg8cG8qVFRr5NDhxbfs9NY/zGDvbgt0GMWXRTi4oMrSkDKthZSWjVezDzPk11AMQ1E+SJSoSXgwUl1rbWPg0O29prkQdfdKQmZcaO5oj7+f3kSPsIOE9+Qn43VOxOWWybkCzSvEbzLgmuov5C8EWYeJgh13qDcNSwNdt4PgAqIq+tikKNUo9qeM9/q20an+i20fatPAcvrRes+xxnIBXmlPDCj02THjX4EulV2KE+nNxFnCrNvFKYp2bEAegJ2neqfeefDDDhn+t7OK9/73v3O3qnEwSyBlt+pEyHfLjv3Cm7Ik7JA5NUQ/nsS3JdC8OYy2i1DWSvi1qsP3ixAVCR7qBVdoOF2Lv5y2GWrJ0EvVcGqaPBnUezMGMdozNjreschNJvRlp3D72dGGQgs00GHyHbIQ5wicC5p+PiZ2z1EUBN7DiDy9ShQPKEDJtISiSrSaPkDPKpW7SxmSfDaLOIxEy4daAupV0gj7yTtrkpEvJjRECpa0kuKFP3/eFVVp/nIjWDzFASfDvYiry90dDrvLxO3tosuvMVfhXcOy/zbyeCkObaFgc3OkO4z2r4X4Vwt18BoRAammiEfgCbnhywl/CmLrSwV1qSjUgALh/XUPkqXCkqerNjYTlZw5NdRUKmheUXHYGwo4Z+xPfDtiHk1N5vRgNL9/qXsgt813spju9kDMGQGiXlrOgIyhArHR5p2B4S3FjRQ/lEoP5+5wN+9tBKYrR79sZXNS8CwR0BPrOoY9GQCYFdxrBtyH6KOWg29FVXNodt2Yvot7ktofcen1zwQJOAr0KTyqF9/TIltO+hS7swSzZMjV368SEPYjrtXfnXNWYltOS2zJAWYeqr0XLrL+iHbbOQLC7Rk0mnizmUt9wdefz4MtfXZNcdKR4LPsOqYyIz5ux90XiCbvcNZJaRa2/dzecv/koLQPbKzFPGxKiUOsHAa5SEGgbWFZE4Y9CBFS4nCuEOgUnVz9XtFAEP4dazc2cxjYLVzaG5msOiOY1O5ZygYMeVZfdKaITg7gMPbkL3Lpzo7QBMXcHmT5YAUeNaSbHxvgg45Jn8r7W72EQP9tF7SPKiPvxo91xkB7MA3JOcZXC1qymTUWqjO038wSShK48kE+qgu7V9rjP5fOCDW3+3338eifxqS7Zq6FSO053c5W2c8wFR4iw==",
      "encryptedKey": "OzSHFXzrXFC5wDvM5NPRkriY/NaC/USvFUPE+f4NZ30tiD2qb8sJM2XT2K7uNIZ05uDLfsJ6/BbEoYC1SOPXcFJMYqRiYFiI9RWrNgR4EtPWZ84RgrmxGcZZjzSqHzjuls8g++cuqJGRV+ePbTRH+z2OuZZu0vMKZiemaZpHL46Ewi9HUnbRDXvOlKFFHmQm5tayZ7m7Mv5iu4T5R3DPEAHlZnGqtP98ToLxUJUS2Eku/iLHXRmhmZXn55Qt5GYiyss8P5/miPqJCu1QG0CStn5Nsl4KvU+I4QYAOcMFWWUAGofOwPWtt8vPh8Bx+7t7BbayKpA4ZUEWWAjC+zASxg==",
      "iv": "SHM0UHU5WXoyTG03TnExWA=="
    }
    ```
  </Tab>

  <Tab title="Sample Decryption Code">
    ```javascript
        const crypto = require('crypto');

        /**
         * Decrypts the symmetric key using the provided private key.
         * @param {string} encryptedKey - Base64 encoded encrypted symmetric key
         * @param {string} privateKey - RSA private key
         * @returns {Buffer} Decrypted symmetric key
         */
        function decryptSymmetricKey(encryptedKey, privateKey) {
            try {
                const encryptedSymmetricKey = Buffer.from(encryptedKey, 'base64');
                const decryptedSymmetricKey = crypto.privateDecrypt(
                    {
                        key: `-----BEGIN RSA PRIVATE KEY-----\n${privateKey}\n-----END RSA PRIVATE KEY-----`,
                        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
                        oaepHash: 'sha256',
                    },
                    encryptedSymmetricKey
                );
                return decryptedSymmetricKey;
            } catch (error) {
                console.error('Error decrypting symmetric key:', error);
                throw new Error('Failed to decrypt symmetric key');
            }
        }

        /**
         * Decrypts the webhook data using the provided symmetric key and IV.
         * @param {string} encryptedWebhookData - Base64 encoded encrypted webhook data
         * @param {Buffer} symmetricKey - Decrypted symmetric key
         * @param {string} payloadIv - Base64 encoded initialization vector
         * @returns {Object} Decrypted webhook data as a JSON object
         */
        function decryptWebhookData(encryptedWebhookData, symmetricKey, payloadIv) {
            try {
                const iv = Buffer.from(payloadIv, 'base64');
                const decipher = crypto.createDecipheriv('aes-256-cbc', symmetricKey, iv);
                let decryptedData = decipher.update(encryptedWebhookData, 'base64', 'utf8');
                decryptedData += decipher.final('utf8');
                return JSON.parse(decryptedData);
            } catch (error) {
                console.error('Error decrypting webhook data:', error);
                throw new Error('Failed to decrypt webhook data');
            }
        }

        // Example usage:
        // const decryptedKey = decryptSymmetricKey(encryptedKey, privateKey);
        // const decryptedData = decryptWebhookData(encryptedWebhookData, decryptedKey, payloadIv);
    ```
  </Tab>
</Tabs>

### Improvements

*   \[**Comments**]: Improved time display in comment dialog by removing "just" from timeago text to make it more concise.

# 3.0.46

### New Features

*   \[**Comments**]: Added "Seen" Feature in the comment dialog. It shows which users have seen the comments. It's automatically enabled in the default component.
    *   If you had previously used a wireframe for the comment dialog, you will need to add the [seen component wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard).

<Frame>
  ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/seen-feature.png)
</Frame>

*   \[**Comments**]: Added a dynamic attribute to identify if the current user is the author of a comment inside the comment thread:
    *   Use the `velt-current-user-author` attribute to conditionally hide options for non-authors:
        ```css
        [velt-current-user-author='false'] app-comment-dialog-thread-card-options {
          display: none;
        }
        ```


# null



# 3.0.49

### Improvements

*   \[**Security**]: Added security updates.

# 3.0.48

### Improvements

*   \[**Comments**]: Added dark mode support for the "Seen By" dropdown in the comment dialog.


# null



# 3.0.50

### New Features

*   \[**Comments**]: Added variant support to the `Velt Comment Pin` component. This is useful for customizing how the pin looks on different elements like charts, tables, etc.
    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentPin variant="CUSTOM_VARIANT" />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comment-pin variant="CUSTOM_VARIANT"></velt-comment-pin>
        ```
      </Tab>
    </Tabs>

*   \[**Access Control**]: Enabled users logged in with "Org A" to access documents belonging to "Org B".
    *   By default, users can only access documents within their own organization.
    *   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.

<Tabs>
  <Tab title="React / Next.js">
    **Using Hook:**

    ```jsx
    useSetDocument(DOCUMENT_ID, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```

    **Using API:**

    ```jsx
    client.setDocument(DOCUMENT_ID, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    Velt.setDocument(DOCUMENT_ID, {
      organizationId: 'ANOTHER_ORGANIZATION_ID'
    });
    ```
  </Tab>
</Tabs>

*   \[**Comments**]: Added ability to toggle the "Seen By" feature:
    <Tabs>
      <Tab title="React / Next.js">
        **Using Props:**

        ```jsx
        <VeltComments seenByUsers={false} />
        ```

        **Using API:**

        ```jsx
        const commentElement = client.getCommentElement();
        commentElement.enableSeenByUsers();
        commentElement.disableSeenByUsers();
        ```
      </Tab>

      <Tab title="Other Frameworks">
        **Using Props:**

        ```html
        <velt-comments seen-by-users="false"></velt-comments>
        ```

        **Using API:**

        ```javascript
        const commentElement = Velt.getCommentElement();
        commentElement.enableSeenByUsers();
        commentElement.disableSeenByUsers();
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Live Selection**]: Improved the live selection UI.

*   \[**Recording**]: Added new wireframes for the recording feature:
    *   Media Source Settings
    *   Recorder All Tool
    *   Recorder All Tool Menu
    *   Recorder Audio Tool
    *   Recorder Video Tool
    *   Recorder Screen Tool
    *   Recording Preview Steps Dialog
    *   Recorder Control Panel
    *   Recorder Player
    *   Video Player
    *   Subtitles
    *   Transcription

*   \[**Comments**]: Updated the empty state UI and added a clear filter button in the sidebar.

*   \[**Comments**]: The "Custom filters" applied by the user are now stored in session storage just like the System filters.

### Improvements

### Bug Fixes

*   \[**Comments**]: Fixed an issue in TipTap editor where the comment dialog closed prematurely after adding a comment in single-thread mode.
*   \[**Comments**]: Fixed an issue on minimap where clicking on it was not navigating to the comment location.
*   \[**Comments**]: Fixed an issue where image attachments in comments were not opening in the lightbox.
*   \[**Comments**]: Fixed an issue where the "AtHere" was not working when the label was set to "all".


# null



# 3.0.52

### Bug Fixes

*   \[**Security**]: Added security updates.

# 3.0.51

### New Features

*   \[**Recorder**]: Added `getRecordingData` API to fetch [recording data](/api-reference/models/RecorderData) including transcript, summary, and recording URLs.

    <Tabs>
      <Tab title="React / Next.js">
        **Using Hook:**

        ```jsx
        const recorderData = useRecordingDataByRecorderId('-O9yTMWmEe5u6YGX8EFV');

        useEffect(() => {
            console.log('Recorder Data: ', recorderData);
        }, [recorderData]);
        ```

        **Using API:**

        ```jsx
        const recorderElement = client.getRecorderElement();

        recorderElement.getRecordingDataByRecorderId("-O9yGiYS8lehOXMpQf4j").subscribe((recorderData) => {
            console.log('Recorder Data: ', recorderData);
        });
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```javascript
        const recorderElement = Velt.getRecorderElement();

        recorderElement.getRecordingDataByRecorderId("-O9yGiYS8lehOXMpQf4j").subscribe((recorderData) => {
            console.log('Recorder Data: ', recorderData);
        });
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Comments**]: In the sidebar, changed default `isExpanded` behavior in custom filtering. If not explicitly set, the first group will be expanded while remaining groups are collapsed.


# null



# 3.0.53

### New Features

*   \[**Comments**]: Now comments are supported on elements with duplicate DOM IDs.
    *   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, eg: Popover comments on a table.
    *   By default, comments appear on all matching elements. Use the `sourceId` attribute to control which element displays the comment dialog when adding a new comment.
    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentTool sourceId="sourceId1" />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comment-tool source-id="sourceId1"></velt-comment-tool>
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Comments**]: In multithread mode, now you can deselect a thread by clicking on the header of the multi-thread dialog.
*   \[**Comments**]: Removed self user from the list of users in the "Seen By" dropdown.
*   \[**Comments**]: Removed users without name and email from the list of users in the "Seen By" dropdown.

### Bug Fixes

*   \[**Tiptap Comments**]: Removed `data-velt-content` attribute. Now the highlighted text styling is only applied to text when there are comments available.
*   \[**Comments**]: Fixed an issue where undefined and null string values appeared in individual and group contact lists.


# null



# 3.0.29

### New Features

*   \[**Comments**]: Added ability to control whether comments inside the annotation should be collapsed.

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltComments collapsedComments={false} />
    ```

    Using API:

    ```javascript
    const commentElement = client.getCommentElement();
    commentElement.enableCollapsedComments();
    commentElement.disableCollapsedComments();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-comments collapsed-comments="false"></velt-comments>
    ```

    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();
    commentElement.enableCollapsedComments();
    commentElement.disableCollapsedComments();
    ```
  </Tab>
</Tabs>

*   \[**Comments**]: Added ability to get comment annotation by ID.

<Tabs>
  <Tab title="React / Next.js">
    Using Hooks:

    ```jsx
    const annotation = useCommentAnnotationById({
      annotationId: '-O6W3jD0Lz3rxuDuqQFx',  // AnnotationID
      documentId: 'document-id'              // DocumentId (Optional)
    });

    React.useEffect(() => {
      console.log('annotation', annotation);
    }, [annotation]);
    ```

    Using API:

    ```javascript
    const commentElement = client.getCommentElement();

    commentElement.getCommentAnnotationById({
      annotationId: '-O6W3jD0Lz3rxuDuqQFx',  // AnnotationID
      documentId: 'document-id'              // DocumentId (Optional)
    }).subscribe((annotation) => {
      console.log('annotation', annotation);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using API:

    ```javascript
    const commentElement = Velt.getCommentElement();

    commentElement.getCommentAnnotationById({
      annotationId: '-O6W3jD0Lz3rxuDuqQFx',  // AnnotationID
      documentId: 'document-id'              // DocumentId (Optional)
    }).subscribe((annotation) => {
      console.log('annotation', annotation);
    });
    ```
  </Tab>
</Tabs>

*   \[**Notifications**]: Added API to mark all notifications as read.
    *   Mark all notifications as read, either globally or for a specific tab.
    *   Using 'all' or 'document' as the `tabId` marks all notifications as read across all tabs (equivalent to calling `setAllNotificationsAsRead()` without arguments).
    *   Using 'for-you' as the `tabId` only marks notifications in the 'for-you' tab as read.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    const notificationElement = client.getNotificationElement();

    // Mark all notifications as read
    notificationElement.setAllNotificationsAsRead();

    // Mark all notifications as read for a specific tab
    notificationElement.setAllNotificationsAsRead({ tabId: 'for-you' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'all' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'document' });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const notificationElement = Velt.getNotificationElement();

    // Mark all notifications as read
    notificationElement.setAllNotificationsAsRead();

    // Mark all notifications as read for a specific tab
    notificationElement.setAllNotificationsAsRead({ tabId: 'for-you' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'all' });
    notificationElement.setAllNotificationsAsRead({ tabId: 'document' });
    ```
  </Tab>
</Tabs>

### Bug Fixes

*   \[**UI Customization**]: Fixed an issue in `velt if` where string comparisions were not working as expected.

# 3.0.28

### New Features

*   \[**Comments**]: Added a reset filter button wireframe in multithread comment dialog.

*   \[**Notifications**]: Added a notifications panel loading state skeleton with wireframes.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    <VeltNotificationsPanelWireframe.Skeleton />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-notifications-panel-skeleton></velt-notifications-panel-skeleton>
    ```
  </Tab>
</Tabs>

### Bug Fixes

*   \[**Comments**]: Fixed an issue where draft comments were not being saved for multithread comments in some cases.
*   \[**Comments**]: Fixed an issue where in inline mode, when editing a comment, the annotation was not being selected.


# null



# 3.0.54

### Improvements

*   \[**Comments**]: The "clear filter" button in the sidebar now only appears when comments are hidden due to active filters, not when there are no comments on the document.

### Bug Fixes

*   \[**Comments**]: Fixed an issue with the Assign feature across different comment modes:
    *   Page mode
    *   Inline mode
    *   Multi-thread mode

*   \[**Comments**]: Fixed an issue where reactions were not updated in focused thread mode.


# null



# 3.0.31

### Improvements

*   \[**Notifications**]: Improved loading state for API calls, now returns null until data is fully loaded.

# 3.0.30

### New Features

*   \[**Notifications**]: Added API to get unread notifications count.
    *   **Sample response:**
    ```javascript
    { 
      forYou: 4, // # of unread notifications in the "For You" tab
      all: 5     // # of unread notifications in the "All" or "Document" tab
    }
    ```

<Tabs>
  <Tab title="React / Next.js">
    Using Hooks:

    ```jsx
    const unreadCount = useUnreadNotificationsCount();

    useEffect(() => {
      console.log('Unread Count', unreadCount);
    }, [unreadCount]);
    ```

    Using API:

    ```javascript
    const notificationElement = client.getNotificationElement();
    notificationElement.getUnreadNotificationsCount().subscribe((data) => {
      console.log('Unread notifications count:', data);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const notificationElement = Velt.getNotificationElement();
    notificationElement.getUnreadNotificationsCount().subscribe((data) => {
      console.log('Unread notifications count:', data);
    });
    ```
  </Tab>
</Tabs>

### Improvements

*   \[**Comments**]: Improved search functionality in @mentions to support spaces in search queries.


# null



# 3.0.33

### Improvements

*   \[**Console Debugger**]: Added logs for `addContext` and `updateContext` methods. The context object is now included in the log event properties for better debugging and tracking.
*   \[**Comments**]: Now comments will be marked as read if opened via the `selectCommentByAnnotationId()` API.

### Bug Fixes

*   \[**Comment Display**]: Improved comment rendering performance for Comments Sidebar.

# 3.0.32

### New Features

*   \[**Comments Sidebar**]: Added a reset filter button to easily clear all applied filters.
    *   This new button allows users to quickly reset all filters in the comments sidebar when no comments are available for the applied filters.
    *   Here is the wireframe for the reset filter button:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebarWireframe.ResetFilterButton />
    ```
  </Tab>

  <Tab title="HTML">
    ```html
    <velt-comments-sidebar-reset-filter-button-wireframe></velt-comments-sidebar-reset-filter-button-wireframe>
    ```
  </Tab>
</Tabs>


# null



# 3.0.35

### Bug Fixes

*   \[**Notifications**]: Fixed an issue where the `document` tab was not visible when user email was not set.

# 3.0.34

### New Features

*   \[**Comments**]: Added support for overlay text commenting in Tiptap editor.
    *   It works with all frontend frameworks that are supported by Tiptap.
    *   You can find the extension [here](https://www.npmjs.com/package/@veltdev/tiptap-velt-comments).

<Steps titleSize="h2">
  <Step title="Install the Velt Tiptap extension">
    ```bash
    npm i @veltdev/tiptap-velt-comments
    ```
  </Step>

  <Step title="Import and add the extension to your Tiptap editor">
    ```javascript
    import { TiptapVeltComments } from '@veltdev/tiptap-velt-comments';

    const editor = new Editor({
      extensions: [
        TiptapVeltComments,
        // ... other extensions
      ],
    });
    ```
  </Step>

  <Step title="Add a comment using the `addTiptapVeltComment` method">
    *   Call this method to add a comment to selected text in the Tiptap editor. You can use this when the user clicks on the comment button in context menu or presses a keyboard shortcut.

    *   Args:
        *   `editor`: instance of the Tiptap editor.
        *   `tiptapVeltCommentConfig`: optional object to set the Comment Annotation's custom metadata.

    *   Example:
        ```javascript
        import { addTiptapVeltComment } from '@veltdev/tiptap-velt-comments';

        addTiptapVeltComment(editor, tiptapVeltCommentConfig);
        ```
  </Step>
</Steps>

### Improvements

*   \[**Console Debugger**]: Added logs for the `updateContactList` method to improve debugging.


# null



# 3.0.37

### Bug Fixes

*   \[**Notifications**]: Fixed an issue where the `unreadCommentsMap` count was not updating correctly when switching between documents with no unread comments.

# 3.0.36

### New Features

*   \[**Comments**]: Added shadowDOM, dark mode, and variant support in standalone Comment Thread component.
    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentThread 
          darkMode={true}
          shadowDom={false}
          variant="component-variant" 
          dialogVariant="dialog-variant"
        />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comment-thread 
          dark-mode="true" 
          shadow-dom="false"
          dialog-variant="dialog-variant"
          variant="component-variant"
        ></velt-comment-thread> 
        ```
      </Tab>
    </Tabs>

### Bug Fixes

*   \[**Comments**]: Fixed an issue where scroll was causing the "Add reply" button to hide.
*   \[**Comments**]: Fixed an issue where the assign to dialog was not closing after assigning a user using the keyboard.


# null



# 3.0.7

### Improvements

*   \[**Comments**]: Pass the `id` attribute on either the `<video>` tag or its parent element. This simplifies the implementation of comments on custom video players.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
      <div id="videoPlayerId">
        <YourVideoPlayerComponent></YourVideoPlayerComponent>
        <VeltCommentPlayerTimeline videoPlayerId="videoPlayerId" totalMediaLength="12"></VeltCommentPlayerTimeline>
        <VeltReactionTool videoPlayerId="videoPlayerId"></VeltReactionTool>
      </div>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
      <div id="videoPlayerId">
        <your-video-player-component></your-video-player-component>
        <velt-comment-player-timeline video-player-id="videoPlayerId" total-media-length="12"></velt-comment-player-timeline>
        <velt-reaction-tool video-player-id="videoPlayerId"></velt-reaction-tool>
      </div>
    ```
  </Tab>
</Tabs>

# 3.0.6

### New Features

*   \[**Comments**]: Added an "Unresolve Comment" button component in the comment dialog. This button is used to unresolve a comment that was previously marked as resolved.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentDialogWireframe.UnresolveButton />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-dialog-unresolve-button-wireframe></velt-comment-dialog-unresolve-button-wireframe>
    ```
  </Tab>
</Tabs>

### Improvements

*   \[**Comments**]: Improved comment text handling by trimming whitespace from `commentText` and `commentHtml` in the comment dialog.

### Bug Fixes

*   \[**Comments**]: Fixed an issue with autocomplete chip shadowDOM not being updated.
*   \[**Notifications**]: Resolved an issue where documents with empty notifications were still being rendered.
*   \[**Users**]: Fixed a bug related to special characters in user names.
*   \[**Comments**]: Fixed an issue where the checkbox in the location filter dropdown in sidebar wasn't updating on selection.
*   \[**Comments**]: Fixed an issue where the status filter menu in the sidebar wasn't closing properly.
*   \[**Recorder**]: Resolved a problem where the device list wasn't updating correctly in the recording settings menu in certain scenarios.


# null



# 3.0.9

### New Features

*   \[**Inline Reactions**]: Added `customReactions` prop for `VeltInlineReactionsSection` component in React, allowing custom emoji definitions:

    ```jsx
    const customReactions = {
      "EMOJI_ID_1": {
        "emoji": "🔥" // You could also set emoji using a url or raw svg definition
      },
      "EMOJI_ID_2": {
        "emoji": "🙌" // You could also set emoji using a url or raw svg definition
      },
      "EMOJI_ID_3": {
        "emoji": "💪" // You could also set emoji using a url or raw svg definition
      }
    }
    <VeltInlineReactionsSection customReactions={customReactions} />
    ```

*   \[**Comments**]: Added `multiThreadMode` prop for `VeltComments` component in React:

    ```jsx
    <VeltComments multiThreadMode={true} />
    ```

### Improvements

*   \[**Comments**]: Updated the unresolved button icon for better understanding.
*   \[**Comments**]: Added types for `enableMultiThreadMode` and `disableMultiThreadMode` API methods.

# 3.0.8

### New Features

*   \[**Comments**]: Added multi-thread support for Comments:

<Tabs>
  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-comments multi-thread-mode="true"></velt-comments>
    ```

    Using API Method:

    ```javascript
    const commentElement = Velt.getCommentElement();
    // To enable multi-thread mode
    commentElement.enableMultiThreadMode();
    // To disable multi-thread mode
    commentElement.disableMultiThreadMode();
    ```
  </Tab>
</Tabs>

*   \[**Inline Reactions**]: Added ability to add list of custom reactions:

<Tabs>
  <Tab title="Other Frameworks">
    Using API Method:

    ```javascript
      const reactionElement = client.getReactionElement();
      const customReactions = {
        "EMOJI_ID_1": {
          "emoji": "🔥" // You could also set emoji using a url or raw svg definition
        },
        "EMOJI_ID_2": {
          "emoji": "🙌" // You could also set emoji using a url or raw svg definition
        },
        "EMOJI_ID_3": {
          "emoji": "💪" // You could also set emoji using a url or raw svg definition
        }
      };
      reactionElement.setCustomReactions(customReactions);
    ```
  </Tab>
</Tabs>

*   \[**UI Customization**]: Added wireframe for MultiThreaded Comment Dialog.
*   \[**UI Customization**]: Added wireframe for Comment Sidebar Button with the new name.

### Improvements

*   \[**Comments**]: Made element binding consistent by using common `targetElementId` attribute in comment feature components:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
      <VeltCommentTool targetElementId={'yourTargetElementId'} />
      <VeltCommentBubble targetElementId={'yourTargetElementId'} />
      <VeltInlineCommentsSection targetElementId={'yourTargetElementId'} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
      <velt-comment-tool target-element-id="yourTargetElementId"></velt-comment-tool>
      <velt-comment-bubble target-element-id="yourTargetElementId"></velt-comment-bubble>
      <velt-inline-comments-section target-element-id="yourTargetElementId"></velt-inline-comments-section>
    ```
  </Tab>
</Tabs>

### Bug Fixes

*   \[**Notifications**]: Fixed an issue where unread icon was not showing up when a comment was added by the user themselves.
*   \[**Notifications**]: Resolved a UI issue where the "All Read" container was showing up while the data was still loading.
*   \[**Notifications**]: Fixed the load more button on all notifications tabs.
*   \[**Notifications**]: Fixed an issue where using the "assign to" options from the thread options menu wasn't generating a notification.
*   \[**Recorder**]: Fixed an issue where recording was saved when minimizing the preview panel.


# null



# 3.0.10

### Bug Fixes

*   \[**Comments**]: Reverted comment sidebar button wireframe changes


# null



# 3.0.11

### New Features

*   \[**UI Customization**]: Added **Conditional Templates**! These let you conditionally show or hide parts of the Velt Component Wireframes.

    *   You can add conditions based on the same data models available in [Template Variables](/ui-customization/template-variables).

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltIf condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 3">
          {/* Content to render if condition is true */}
        </VeltIf>
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-if condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 3">
          <!-- Content to render if condition is true -->
        </velt-if>
        ```
      </Tab>
    </Tabs>

*   \[**UI Customization**]: You can now customize confirmation dialogs (eg: Delete thread, Delete recorder etc) for each feature by defining variants.
    *   Supported variants: `recorder`, `comment`, `arrow`, `area`.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
      <VeltWireframe>
        <VeltConfirmDialogWireframe variant="comment">
          <div>
            <VeltConfirmDialogWireframe.Title>
              Custom Title
            </VeltConfirmDialogWireframe.Title>

            <VeltConfirmDialogWireframe.Message>
              Custom Message
            </VeltConfirmDialogWireframe.Message>

            <VeltConfirmDialogWireframe.RejectButton>
              Custom Reject Button
            </VeltConfirmDialogWireframe.RejectButton>

            <VeltConfirmDialogWireframe.ApproveButton>
              Custom Approve Button
            </VeltConfirmDialogWireframe.ApproveButton>
          </div>
        </VeltConfirmDialogWireframe>
      </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
      <velt-wireframe style="display:none">
        <velt-confirm-dialog-wireframe variant="comment">
          <div>
            <velt-confirm-dialog-title-wireframe>
              Custom Title
            </velt-confirm-dialog-title-wireframe>

            <velt-confirm-dialog-message-wireframe>
              Custom Message
            </velt-confirm-dialog-message-wireframe>

            <velt-confirm-dialog-reject-button-wireframe>
              Custom Reject Button
            </velt-confirm-dialog-reject-button-wireframe>

            <velt-confirm-dialog-approve-button-wireframe>
              Custom Approve Button
            </velt-confirm-dialog-approve-button-wireframe>
          </div>
        </velt-confirm-dialog-wireframe>
      </velt-wireframe>
    ```
  </Tab>
</Tabs>

*   \[**UI Customization**]: Added two new global [Template Variables](/ui-customization/template-variables):
    *   `unreadCommentAnnotationCount`: Number of unread comment annotations on the current document.
    *   `unreadCommentCount`: Total number of unread comments on the current document.

*   \[**Comments**]: Added `updateContext` method for updating custom metadata (`context`) on comment annotations. [Learn more](/async-collaboration/comments/customize-behavior/custom-metadata#2-update-custom-metadata-on-comment-annotation). This method is available in two scenarios:

    1.  **In the `onCommentUpdate` event callback:**
        Use this to update the context when a comment is modified.

    2.  **Via the `updateContext` API 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.

### Improvements

*   \[**Comments**]: Updated the icon for the Unresolve button.
*   \[**Comments**]: Whenever the comment sidebar is opened using the button or the api, any open comment dialog will be closed.
*   \[**Comments**]: Made position of the reaction tool consistent across different states and content types in the comment dialog.

### Bug Fixes

*   \[**Comments**]: Fixed the flicker issue when new popover comment thread was created. This only happened when the triangle component was disabled.
*   \[**Comments**]: Fixed minor rendering issue with the @mention chip when it was added at the end of the content.
*   \[**Velt Components**]: Reduced the default z-index for all Velt Components to prevent them from going over the host app's header or any other important UI elements.
*   \[**Comments**]: Fixed menu overlay positioning to stay with its trigger during page scrolling.


# null



# 3.0.14

### Bug Fixes

*   \[**Comments**]: Fixed a bug related to updating comment annotations.

# 3.0.13

### New Features

*   \[**Comments**]: Added Draft State:
    *   Empty comments are no longer saved.
    *   Partial comments are saved as drafts, visible only to the author.
    *   Draft creation:
        *   Comment is saved as draft when the user adds text, recording, or attachment and closes the comment dialog without submitting.
        *   On first attempt to close: Dialog shakes to indicate draft status.
        *   On second attempt: the comment is saved as draft and the dialog closes.
    *   Added a visual indicator for draft comments in the dialog.
    *   If you had previously used a wireframe for the comment dialog, you will need to add the [draft wireframe](/ui-customization/features/async/comments/comment-dialog/subcomponents/body/subcomponents/threadcard).

# 3.0.12

### Improvements

*   \[**UI Customization**]: Refactored `velt if` and `velt data` logic for improved performance.


# null



# 3.0.16

### New Features

*   \[**Comments**]: Added a new `atHereDescription` prop to customize the description that appears for the @here mention.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    Using Props:

    ```jsx
    <VeltComments atHereDescription="Notify all users in this document" />
    ```

    Using API Method:

    ```jsx
    const contactElement = useContactUtils();

    useEffect(() => {
      contactElement.setAtHereDescription('Notify all users in this document');
    }, [contactElement]);
    ```
  </Tab>

  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltComments atHereDescription="Notify all users in this document" />
    ```

    Using API Method:

    ```jsx
    const contactElement = client.getContactElement();
    contactElement.setAtHereDescription('Notify all users in this document');
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-comments at-here-description="Notify all users in this document"></velt-comments>
    ```

    Using API Method:

    ```javascript
    const contactElement = Velt.getContactElement();
    contactElement.setAtHereDescription('Notify all users in this document');
    ```
  </Tab>
</Tabs>

*   \[**Comments**]: Added the `getSelectedComments()` API to get the currently selected comment annotations.
    *   This returns an array of [`CommentAnnotation`](/api-reference/models/CommentAnnotation) objects.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    const commentElement = client.getCommentElement();
    const subscription = commentElement.getSelectedComments().subscribe((selectedComments) => {
      console.log('Selected comments:', selectedComments);
    });

    ```

    Unsubscribe from the subscription when you're done:

    ```jsx
    subscription?.unsubscribe()

    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    const commentElement = Velt.getCommentElement();
    const subscription = commentElement.getSelectedComments().subscribe((selectedComments) => {
      console.log('Selected comments:', selectedComments);
    });
    ```

    Unsubscribe from the subscription when you're done:

    ```js
    subscription?.unsubscribe()
    ```
  </Tab>
</Tabs>

### Bug Fixes

*   \[**Comments**]: Fixed an issue where the [custom list](/async-collaboration/comments/customize-behavior/custom-lists#1-add-custom-lists-on-comment-annotation) chip tooltip icon was not displayed.
*   \[**Comments**]: Fixed an issue where the reaction tooltip in the [comment player timeline component](/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup) was getting distorted on hover.
*   \[**Comments**]: Fixed an issue where the reaction bubble on the [comment player timeline component](/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup) had a transparent background.

# 3.0.15

### New Features

*   \[**Comments**]: Added a Minimal Filter Dropdown Component for the Multithread Comment Dialog. This provides basic filtering and sorting options, including:
    *   Sorting: by date, by unread status
    *   Filtering: unread comments, read comments, resolved comments

### Improvements

*   \[**Comments**]: Updated multithread behavior to ensure only one composer is open at a time.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where the Floating Mode Comment Sidebar would not close when clicked outside.
*   \[**Comments**]: Resolved a problem where sidebar dropdowns were not closing when clicked on the trigger button again.
*   \[**Comments**]: Fixed an issue where the Add Reply button wasn't working in Inline Comment Section.


# null



# 3.0.17

### Improvements

*   \[**Notifications**]: Added an empty state for the document and all tabs in the notification panel.
*   \[**Notifications**]: Added type definition for the `tabConfig` prop to improve TypeScript support.

### Bug Fixes

*   \[**Notifications**]: Fixed an issue where React props for customizing the notification panel were not working as expected.


# null



# 3.0.18

### New Features

*   \[**Comments**]: Added a new prop to control the use of ShadowDOM for [Persistent Comment Mode](/async-collaboration/comments/customize-behavior/modes#persistent-comment-mode) banner.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltComments persistentCommentShadowDom={false} />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comments persistent-comment-shadow-dom="false"></velt-comments>
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Comments**]: Action buttons are now consistently displayed across all states (default, hover, selection) of the comment dialog and can be customized via CSS alone.

### Bug Fixes

*   \[**Notifications**]: Fixed an issue where the `tabConfig` React props was not working as expected.


# null



# 3.0.22

### Bug Fixes

*   \[**Comments**]: Fixed a bug where clicking on one's own reaction on the [Velt Comment Player Timeline](/async-collaboration/comments/setup/video-player-setup/custom-video-player-setup) didn't toggle it correctly.

# 3.0.21

### Improvements

*   \[**Comments**]: Added `createdAt` field for [CommentAnnotation](/api-reference/models/CommentAnnotation) model. This can now be used to sort annotations in ascending order of creation.
*   \[**Comments**]: Added `isEdited` and `editedAt` fields in [Comment](/api-reference/models/Comment) model. This can now used to indicate if and when a comment is edited.
*   \[**Comments**]: In multithread mode, the count on the header is now synced with the total threads visible after all the fitlers are applied.
*   \[**Comments**]: Inline and multi-thread comments are now sorted in ascending order by the `createdAt` field, maintaining backward compatibility.
*   \[**Comments**]: Improved the behavior where the mutlthread container was auto-closing when one of the threads was deleted or resolved.

### Bug Fixes

*   \[**Comments**]: Fixed a bug where deleting a recording in a single-comment thread incorrectly triggered the Delete Thread dialog.
*   \[**Comments**]: Fixed a bug where resolved comment threads weren't disappearing in [inline comment mode](/async-collaboration/comments/setup/inline-comments).

# 3.0.20

### New Features

*   \[**Notifications**]: Added a configurable option to show read notifications in the "For You" tab. By default, read notifications are removed from the "For You" tab.

<Tabs>
  <Tab title="React / Next.js with Hooks">
    Using Props:

    ```jsx
    <VeltNotificationsTool readNotificationsOnForYouTab={true} />
    <VeltNotificationsPanel readNotificationsOnForYouTab={true} />
    ```

    Using APIs:

    ```jsx
    const notificationElement = useNotificationUtils();
    // Enable to keep read notifications in the for you tab
    notificationElement.enableReadNotificationsOnForYouTab();
    // Disable to hide read notifications in the for you tab
    notificationElement.disableReadNotificationsOnForYouTab();
    ```
  </Tab>

  <Tab title="React / Next.js">
    Using Props:

    ```jsx
    <VeltNotificationsTool readNotificationsOnForYouTab={true} />
    <VeltNotificationsPanel readNotificationsOnForYouTab={true} />
    ```

    Using APIs:

    ```jsx
    const notificationElement = client.getNotificationElement();
    // Enable to keep read notifications in the for you tab
    notificationElement.enableReadNotificationsOnForYouTab();
    // Disable to hide read notifications in the for you tab
    notificationElement.disableReadNotificationsOnForYouTab();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-notifications-tool read-notifications-on-for-you-tab="true">
    </velt-notifications-tool>
    <velt-notifications-panel read-notifications-on-for-you-tab="true">
    </velt-notifications-panel>
    ```

    Using API:

    ```html
    <script>
      // Using APIs
      const notificationElement = Velt.getNotificationElement();
      // Enable to keep read notifications in the for you tab
      notificationElement.enableReadNotificationsOnForYouTab();
      // Disable to hide read notifications in the for you tab
      notificationElement.disableReadNotificationsOnForYouTab();
    </script>
    ```
  </Tab>
</Tabs>

For more details on customizing notifications behavior, refer to the [Notifications Behavior](/async-collaboration/notifications/customize-behavior) section.

### Improvements

*   \[**REST API**]: Added advanced querying and pagination on REST APIs for improved performance and functionality.
*   \[**Comments**]: Made the rendering of comment dialog action buttons configurable via CSS on hover or selection.

### Bug Fixes

*   \[**Comments**]: Resolved a rare bug where the triangle pin component would cause the comment dialog to flicker on hover in popover comment mode.
*   \[**Autocomplete dropdowns**]: Fixed a bug where the autocomplete dropdown component would not apply the `--velt-default-font-family`.
*   \[**Notifications**]: Fixed a bug occurring when marking all notifications as read in large notification data sets.

# 3.0.19

### New Features

*   \[**Comments**]: Added a standalone Comment Composer component. Now you can use this in combination with [Velt Comment Threads](/async-collaboration/comments/standalone-components/comment-thread/overview) component to embed commenting experiences in custom ways.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltCommentComposer />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-comment-composer></velt-comment-composer>
        ```
      </Tab>
    </Tabs>

*   \[**Inline Comments**]: Added single thread option to inline comments. By default, it will be in multithread mode.
    Default value: `true`
    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltInlineCommentsSection multiThread={false} />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-inline-comments-section multi-thread="false">
        </velt-inline-comments-section>
        ```
      </Tab>
    </Tabs>


# null



# 3.0.23

### New Features

*   \[**Webhooks**]: Added configuration option for base64 encoding of webhook payloads (disabled by default).
    *   Addresses issues with payloads containing HTML tags that may fail due to strict endpoint policies.
    *   Ensures payload validity and processability by your endpoint.
    *   Example of decoding a base64 encoded payload:

```js
const encodedData="eyJ0ZXN0IjoxLCJ0ZXN0MSI6IjxkaXY+PC9kaXY+In0="
const decodedData = Buffer.from(encodedData, 'base64').toString('utf-8');
console.log(JSON.parse(decodedData));
```

### Improvements

*   \[**Comments**]: Significant enhancements to the comments UX in multithread mode:
    *   Implemented smooth auto-scroll animation to new threads for improved visibility
    *   Added a new comment button to the header for easier thread creation
    *   Refined composer show/hide logic for a more intuitive user experience
    *   Shortened the displayed timestamp format

*   \[**Comments**]: Improved the UI for [custom autocomplete dropdown chip](async-collaboration/comments/customize-behavior/custom-lists#2-add-custom-lists-on-comment).

*   \[**Notifications**]: Notifications feature and API no longer require documentId to be set for initialization.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where the custom autocomplete chip would fail to render if the same chip is added multiple times.


# null



# 3.0.25

### Bug Fixes

*   \[**Comments**]: Fixed an issue where the composer would throw a console error on Firefox. This didn't have any impact on functionality or UX.
*   \[**Comments**]: Fixed reply button toggle issue.

# 3.0.24

### Improvements

*   \[**Comments**]: Improvements to the comments UX in multithread mode.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where sign in button was showing up for logged in users on mobile. This only impacted customers where signIn button was enabled.


# null



# 3.0.2

### New Features

*   \[**Reactions**]: Added [inline reaction section](/async-collaboration/reactions/setup) feature component.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltInlineReactionsSection 
          targetReactionElementId="containerId"
        />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-inline-reactions-section target-reaction-element-id="containerId"></velt-inline-reactions-section>
        ```
      </Tab>
    </Tabs>

### Improvements

*   \[**Comments**]: Truncated video timeline comment card to 100 characters for improved readability.
*   \[**Users**]: Limited user names to a maximum of 20 characters and disallowed URLs in names for security purposes.

### Bug Fixes

*   \[**Comments**]: Resolved an issue with the unread indicator in the comment dialog.


# null



# 3.0.26

### Improvements

*   \[**Comments**]: Renamed `multiThreadMode` prop to `multiThread` for improved clarity and consistency.
*   \[**Comments**]: Removed the "0 comments" from the multithread container header, when the first thread is created.
*   \[**Comments**]: The comment pin bubble count in multithread mode would sync with the number of unresolved comments in the multithread container.
*   \[**Comments**]: Added an unread indicator on the comment pin bubble in multithread mode to help users quickly identify new or unread comments.
*   \[**UI Customization**]: Added improvements to the `velt if` conditional rendering logic.

### Bug Fixes

*   \[**Comments**]: Fixed an issue where the menu trigger button would hide when the mouse moved on the menu.
*   \[**Notifications**]: Resolved an issue where `documentName` wasn't displayed on the notification item in the notification panel.


# null



# 3.0.3

### New Features

*   \[**Comments**]: Added a minimal filtering and sorting dropdown in the sidebar wireframe. By default it's not enabled. You need to explicitly add the wireframe to the sidebar. It includes options like:
*   Filter by `All`
*   Filter by `Unread`
*   Filter by `Read`
*   Filter by `Resolved`
*   Sort by `Unread`
*   Sort by `Last Updated Timestamp`

### Bug Fixes

*   \[**Comments**]: Fixed an issue where the dialog was overflowing out of the screen in some cases.


# null



# 3.0.4

### New Features

*   \[**Comments**]: Added persistent comment mode banner wireframe.

*   \[**API**]: Added `getDocumentMetadata` method to get the current document's metadata. It returns a subscription with [`DocumentMetadata`](/api-reference/models/DocumentMetadata) object.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    client.getDocumentMetadata().subscribe((documentMetadata) => {
        console.log("Current document metadata: ", documentMetadata);
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    Velt.getDocumentMetadata().subscribe((documentMetadata) => {
      console.log("Current document metadata: ", documentMetadata);
    });
    ```
  </Tab>
</Tabs>

### Improvements

*   \[**Comments**]: The persistent comment banner now inherits the shadow DOM property from `Velt Comments`.


# null



# 3.0.5

### New Features

*   \[**Comments**]: Added a minimal location filter in the sidebar wireframe for basic location based filtering. By default it's not enabled. You need to explicitly add the wireframe to the sidebar.
*   \[**Sidebar**]: Added `Floating Mode` for Comments Sidebar. This allows the sidebar panel to appear as an overlay on top of the sidebar button when clicked.

    <Tabs>
      <Tab title="React / Next.js">
        ```jsx
        <VeltSidebarButton floatingMode={true} />
        ```
      </Tab>

      <Tab title="Other Frameworks">
        ```html
        <velt-sidebar-button floating-mode="true"></velt-sidebar-button>
        ```
      </Tab>
    </Tabs>

### Bug Fixes

*   \[**Comments**]: Fixed a bug where clicking the "replies" button in the sidebar comment dialog incorrectly opened the comment dialog on the DOM. This issue only affected implementations using the sidebar comment dialog wireframe.


# Generating Auth Tokens



<Steps>
  <Step title="Go to the Velt Console">
    Open the Velt Console at [console.velt.dev](https://console.velt.dev)
  </Step>

  <Step title="Click Generate Token button">
    Under the Auth Token section, click on Generate Token button:

    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/auth-token-generate.png)
  </Step>

  <Step title="Copy the generated token">
    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/auth-token.png)
  </Step>
</Steps>


# null



## Whitelisting Rules for Content Security Policy (CSP)

If you have a Content Security Policy (CSP) enabled in your app configuration, ensure that the following URLs are whitelisted:

*   `https://cdn.velt.dev` (`script-src`)
*   `https://cdn.velt.dev/*` (`script-src`)
*   `https://api.velt.dev` (`connect-src`)
*   `https://api.velt.dev/*` (`connect-src`)
*   `https://*.api.velt.dev` (`connect-src`)
*   `https://*.googleapis.com` (`connect-src`, `img-src`)
*   `https://*.firebaseio.com` (`connect-src`, `script-src`)
*   `wss://*.firebaseio.com` (`connect-src`)


# JWT Tokens

Generate JWT Tokens for additional security

## Overview

`JWT Tokens` is an optional feature to add additional authentication security to our `client.identify()` method to prevent user impersonation.

<Steps>
  <Step title="Enable JWT Tokens in your console">
    Go to [https://console.velt.dev](https://console.velt.dev/dashboard/config/general) and enable the toggle for `Require JWT Token`. The toggle is listed at the very bottom of the page.

    <Warning>JWT Tokens won't work unless you enable it in your console.</Warning>
  </Step>

  <Step title="Create a server endpoint for generating and sending JWT Tokens to the client">
    Create a server endpoint that will be used to generate and send a `JWT Token` to the client.

    Example server endpoint code:

    ```jsx
    app.get('/generate-velt-jwt-token', async (req,res) => {
        const veltAuthToken = await generateVeltAuthToken(req.body.userId)
        res.json(veltAuthToken)
    })
    ```
  </Step>

  <Step title="Generate a JWT Token using Velt's REST API">
    In your server endpoint, call our `https://api.velt.dev/v1/auth/token/get` endpoint to generate a `JWT Token`.

    Example server code:

    ```jsx
    async function generateVeltAuthToken(userId: string) {
      const url = "https://api.velt.dev/v1/auth/token/get";
      const body = {
        data: {
          userId: userId, // Unique user id of your user
          apiKey: "YOUR_VELT_API_KEY",
          authToken: "YOUR_CLIENT_AUTH_TOKEN", // Get this token from console.velt.dev
          userProperties: {
            isAdmin: true, // Set to true if you want to set user as admin
            organizationId: "YOUR_ORGANIZATION_ID", // If organizationId is provided here then we will validate it with the organizationId used in the identify call
            email: "USER_EMAIL", // If email is provided here then we will validate it with the email used in the identify call
          }
        },
      };

      try {
        const response = await fetch(url, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(body),
        });

        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();
        return data?.result?.data?.token;
      } catch (error) {
        console.error("Error:", error);
      }
    }
    ```

    ### Request Body:

    <Info>
      To get your Auth Token that is required for your request body, [read here](/security/auth-tokens).
    </Info>

    | Field                           | Required | Description                                                                                                                                               |
    | ------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `apiKey`                        | Yes      | Velt API Key                                                                                                                                              |
    | `authToken  `                   | Yes      | Auth Token from the Velt console                                                                                                                          |
    | `userId `                       | Yes      | Unique user id of the user                                                                                                                                |
    | `userProperties.isAdmin`        | No       | Set to `true` if you want to set user as `admin`. This is the only way to set a user as an `admin` User                                                   |
    | `userProperties.organizationId` | No       | If `organizationId` is provided, it will be validated with the `organizationId` used in the identify call. Recommended if you are setting organizationId. |
    | `userProperties.email`          | No       | If `email` is provided, it will be validated with the `email` used in the identify call. Recommended if you are setting email.                            |

    ```jsx
    {
      "data": {
        "apiKey": "YOUR_API_KEY", //Velt API Key
        "authToken": "YOUR_AUTH_TOKEN", // Auth Token from the Velt console
        "userId": "yourUserId", // unique user id of the user you are generating a JWT Token for
        "userProperties": {
            isAdmin: true, // Set to true if you want to set user as admin
            organizationId: "YOUR_ORGANIZATION_ID", // If organizationId is provided here then we will validate it with the organizationId used in the identify call
            email: "USER_EMAIL", // If email is provided here then we will validate it with the email used in the identify call
        }
      }
    }
    ```

    ### Success Response:

    ```jsx
    {
      "result": {
        "status": "success",
        "message": "Token generated successfully.",
        "data": {
          "token": "YOUR_JWT_TOKEN"
        }
      }
    }
    ```

    ### Failure Response:

    ```jsx
    {
      "error": {
        "message": "Auth token not found.",
        "status": "INVALID_ARGUMENT"
      }
    }

    ```

    <Warning>Make sure to generate the JWT Token from your server, not your client. Otherwise, your JWT Token will not be secure.</Warning>
  </Step>

  <Step title="Call your server endpoint from your client to pass your JWT Token to your client">
    Call your server endpoint from your client to pass your `JWT Token` to your client.

    ```jsx
      const yourJWTToken = await callToYourServerToGetJWTToken(userId)
    ```
  </Step>

  <Step title="Pass the JWT Token to client.identify()">
    Once the JWT Token is generated, you can pass it into the `client.identify()` method. The `client.identify()` method has an optional second parameter that takes in a configuration object that includes the `JWT Token` as a field.

    ```jsx
      const yourJWTToken = await callToYourServerToGetJWTToken(userId)
      client.identify(user, {
        authToken: yourJWTToken,
      });
    ```
  </Step>

  <Step title="Your All Done!">
    You are all done! Now you have added an additional level of security with `JWT Tokens`.
  </Step>
</Steps>

<RequestExample>
  ```jsx Server Code
  import express from 'express';

  const app = express();
  const PORT = 8080;

  async function generateVeltAuthToken(userId) {
    const url = "https://api.velt.dev/v1/auth/token/get";
    const body = {
      data: {
        userId: userId, // Unique user id of your user
        apiKey: "YOUR_VELT_API_KEY",
        authToken: "YOUR_CLIENT_AUTH_TOKEN", // Get this token from console.velt.dev
        userProperties: {
          isAdmin: true, // Set to true if you want to set user as admin
          organizationId: "YOUR_ORGANIZATION_ID", // If organizationId is provided here then we will validate it with the organizationId used in the identify call
          email: "USER_EMAIL", // If email is provided here then we will validate it with the email used in the identify call
        }
      },
    };

    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(body),
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const data = await response.json();
      return data?.result?.data?.token;
    } catch (error) {
      console.error("Error:", error);
    }
  }

  app.get('/generate-velt-jwt-token', async (req,res) => {
      const veltAuthToken = await generateVeltAuthToken(req.body.userId)
      res.json(veltAuthToken)
  })

  app.listen(PORT, () => {
    console.log(`JWT Server listening on port ${PORT}`);
  });

  ```

  ```jsx Client Code
  import { useVeltClient } from "@veltdev/react";
  import { useEffect, useState } from "react";

  export default function YourAuthComponent() {
    let [user, setUser] = useState(null);

    const userService = () => {
      return {
        uid: "user1",
        displayName: "User 1",
        email: "user1@velt.dev",
        photoURL: "https://i.pravatar.cc/301",
        organizationId: "YOUR_ORGANIZATION_ID"
      };
    };

    // Fetch user data from user service
    let yourAuthenticatedUser = userService();

    // Get the Velt Client
    const { client } = useVeltClient();

    // Call to your Server to get JWT Token
    async function callToYourServerToGetJWTToken(userId){

      let baseUrl = "your-server.com"

      let result = await fetch(`${baseUrl}/generate-velt-jwt-token`, {
        method: "POST", 
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          userId:userId
        }),
      })

      let data = await result.json();
      return data;

    }


    useEffect(() => {
      const initVelt = async () => {
        if (client && yourAuthenticatedUser) {
          const { uid, displayName, email, photoURL } = yourAuthenticatedUser;

          // Create the Velt user object
          const user = {
            userId: uid,
            name: displayName,
            email: email,
            photoUrl: photoURL,
            organizationId: "YOUR_ORGANIZATION_ID"
          };


          //Get JWT Token from your server
          const yourJWTToken = await callToYourServerToGetJWTToken(user.userId)

          // Identify the user with the Velt client, with JWT Token
          await client.identify(user, {
              authToken: yourJWTToken,
          });

          setUser(user);
        }
      };
      initVelt().catch(console.error);
    }, [client]);

    return <div>User: {user?.userId}</div>;
  }


  ```
</RequestExample>


# Proxy Server



If you want to use a Proxy Server, such as `nginx`, to redirect to the Velt SDK instead of using our servers, you can pass a `proxyDomain` to the configuration prop of the `VeltProvider`.

Example:

```jsx
<VeltProvider 
  config={{
    proxyDomain: 'https://cdn.velt.dev'
  }}
></VeltProvider>
```

## Proxy Path

We will append `/lib/sdk@[VERSION_NUMBER]/velt.js` to the end of your `proxyDomain` to use as the full proxy path. Make sure that you host the proxy in the correct path.

Example: if you pass `https://cdn.velt.dev` as the `proxyDomain`, we will use `https://cdn.velt.dev/lib/sdk@[VERSION_NUMBER]/velt.js` as the full proxy path.


# Conditional Templates



*   Conditional Templates let you conditionally show or hide parts of the Velt Component Wireframes.
*   You can add conditions based on the same data models available in [Template Variables](/ui-customization/template-variables).

## Usage

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltIf condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 3">
      {/* Content to render if condition is true */}
    </VeltIf>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-if condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 3">
      <!-- Content to render if condition is true -->
    </velt-if>
    ```
  </Tab>
</Tabs>

## Syntax

The condition is specified as a string that will be evaluated as a JavaScript expression. You can use:

*   Comparison operators: `===`, `==`, `!==`, `>`, `<`, `>=`, `<=`
*   Logical operators: `&&`, `||`, `!`
*   Template variables enclosed in curly braces: `{variable.property}`

## Example Usage

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    {/* 1. Show content only for open annotations: */}
    <VeltIf condition="{annotation.status.id} === 'OPEN'">
      <p>This annotation is currently open.</p>
    </VeltIf>

    {/* 2. Display a message for annotations with more than 5 comments: */}
    <VeltIf condition="{annotation.comments.length} > 5">
      <p>This is a popular annotation!</p>
    </VeltIf>

    {/* 3. Combine multiple conditions: */}
    <VeltIf condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 0">
      <p>This is a new open annotation without any comments yet.</p>
    </VeltIf>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <!-- 1. Show content only for open annotations: -->
    <velt-if condition="{annotation.status.id} === 'OPEN'">
      <p>This annotation is currently open.</p>
    </velt-if>

    <!-- 2. Display a message for annotations with more than 5 comments: -->
    <velt-if condition="{annotation.comments.length} > 5">
      <p>This is a popular annotation!</p>
    </velt-if>

    <!-- 3. Combine multiple conditions: -->
    <velt-if condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 0">
      <p>This is a new open annotation without any comments yet.</p>
    </velt-if>
    ```
  </Tab>
</Tabs>


# Dark Mode



<Tabs>
  <Tab title="React / Next.js">
    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/dark-light-mode.png)

    You can customize components by enabling Dark Mode.

    By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

    To enable Dark Mode for all components:

    ```jsx
    let client = useVeltClient();
    client.setDarkMode(true);
    ```

    To enable Dark Mode for individual components:

    ```jsx
    <VeltComments 
      darkMode={true}
      dialogDarkMode={true}
      pinDarkMode={true}
      textCommentToolDarkMode={true}
      textCommentToolbarDarkMode={true}
    />

    <VeltPresence darkMode={true} />
    <VeltCommentsSidebar darkMode={true} />
    <VeltSidebarButton darkMode={true} />
    <VeltCommentBubble darkMode={true} />
    <VeltCommentTool darkMode={true}/>
    <VeltHuddle darkMode={true} />
    <VeltArrows darkMode={true} />
    ```

    API Method:

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/dark-light-mode.png)

    You can customize components by enabling Dark Mode.

    By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

    To enable Dark Mode for all components:

    ```jsx
    let client = useVeltClient();
    client.setDarkMode(true);
    ```

    To enable Dark Mode for individual components:

    ```html
    <velt-comments 
      dark-mode="true"
      dialog-dark-mode="true"
      pin-dark-mode="true"
      text-comment-tool-dark-mode="true"
      text-comment-toolbar-dark-mode="true"
    >
    </velt-comments>


    <velt-presence dark-mode="true"></velt-presence>
    <velt-comments-sidebar dark-mode="true"></velt-comments-sidebar>
    <velt-huddle dark-mode="true"></velt-huddle>
    <velt-arrows dark-mode="true"></velt-arrows>
    <velt-comment-bubble dark-mode="true"></velt-comment-bubble>
    <velt-sidebar-button dark-mode="true"></velt-sidebar-button>
    <velt-comment-tool dark-mode="true"></velt-comment-tool>

    ```

    API Method:

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js

  import { VeltComments, useVeltClient } from '@veltdev/react';

  import { useEffect } from 'react'

  export default function YourDocument() {
    const { client } = useVeltClient();  

    useEffect(()=>{
      if(client){
        const commentElement = client.getCommentElement();
        commentElement.enableDarkMode();
        commentElement.disableDarkMode(); 
      }
    })

    return (
      <div>
          <VeltComments 
            darkMode={true}
            dialogDarkMode={true}
            pinDarkMode={true}
            textCommentToolDarkMode={true}
            textCommentToolbarDarkMode={true}
          />

          <VeltPresence darkMode={true} />
          <VeltCommentsSidebar darkMode={true} />
          <VeltSidebarButton darkMode={true} />
          <VeltCommentBubble darkMode={true} />
          <VeltCommentTool darkMode={true}/>
          <VeltHuddle darkMode={true} />
          <VeltArrows darkMode={true} />
      </div>
    )
  }
  ```

  ```html HTML
  <body>
    <velt-comments 
      dark-mode="true"
      dialog-dark-mode="true"
      pin-dark-mode="true"
      text-comment-tool-dark-mode="true"
      text-comment-toolbar-dark-mode="true"
    >
    </velt-comments>


    <velt-presence dark-mode="true"></velt-presence>
    <velt-comments-sidebar dark-mode="true"></velt-comments-sidebar>
    <velt-huddle dark-mode="true"></velt-huddle>
    <velt-arrows dark-mode="true"></velt-arrows>
    <velt-comment-bubble dark-mode="true"></velt-comment-bubble>
    <velt-sidebar-button dark-mode="true"></velt-sidebar-button>
    <velt-comment-tool dark-mode="true"></velt-comment-tool>
    <script>
      if(Velt){
          const commentElement = Velt.getCommentElement();
          commentElement.enableDarkMode(); 
          commentElement.disableDarkMode(); 
      }
      </script>
  </body>
  ```
</RequestExample>


# Remove Shadow DOM



<Tabs>
  <Tab title="React / Next.js">
    ## Disable ShadowDOM

    If you want to customize components using global CSS, you can do so by disabling the ShadowDOM.

    By default, a ShadowDOM is used with certain components to ensure that your application's CSS does not interfere with the styling of the SDK components.

    If you want your application's CSS to affect the styling of certain SDK components, you can disable the ShadowDOM.

    There are different properties and methods that can be used to disable the ShadowDOM of individual components.

    Examples:

    ```jsx
    <VeltComments
      shadowDom={false}
      dialogShadowDom={false}
      pinShadowDom={false}
      textCommentToolShadowDom={false}
      textCommentToolbarShadowDom={false}
    />


    <VeltCommentBubble shadowDom={false} />
    <VeltCommentTool shadowDom={false} />
    <VeltSidebarButton shadowDom={false} />
    <VeltCommentsSidebar shadowDom={false} />
    <VeltCommentPlayerTimeline shadowDom={false} />
    <VeltVideoPlayer shadowDom={false} />
    <VeltNotificationsTool shadowDom={false} panelShadowDom={false} />
    <VeltNotificationsPanel shadowDom={false} />

    ```

    API Methods:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enablePinShadowDOM();
    commentElement.disablePinShadowDOM();
    commentElement.enableDialogShadowDOM();
    commentElement.disableDialogShadowDOM();
    commentElement.enableSidebarShadowDOM();
    commentElement.disableSidebarShadowDOM();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ## Disable ShadowDOM

    If you want to customize components using global CSS, you can do so by disabling the ShadowDOM.

    By default, a ShadowDOM is used with certain components to ensure that your application's CSS does not interfere with the styling of the SDK components.

    If you want your application's CSS to affect the styling of certain SDK components, you can disable the ShadowDOM.

    There are different properties and methods that can be used to disable the ShadowDOM of individual components.

    ```jsx
    <velt-comments
    	shadow-dom="false"
    	dialog-shadow-dom="false"
    	pin-shadow-dom="false"
    	text-comment-tool-shadow-dom="false"
    	text-comment-toolbar-shadow-dom="false"
    ></velt-comments>


    <velt-comment-bubble shadow-dom="false"></velt-comment-bubble>
    <velt-comment-tool  shadow-dom="false"></velt-comment-tool>
    <velt-sidebar-button  shadow-dom="false"></velt-sidebar-button>
    <velt-comments-sidebar shadow-dom="false"></velt-comments-sidebar>
    <velt-comment-player-timeline shadow-dom="false"></velt-comment-player-timeline>
    <velt-video-player shadow-dom="false"></velt-video-player>
    <velt-notifications-tool shadow-dom="false" panel-shadow-dom="false"></velt-notifications-tool>
    <velt-notifications-panel shadow-dom="false"></velt-notifications-panel>
    ```

    API Methods:

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enablePinShadowDOM();
    commentElement.disablePinShadowDOM();
    commentElement.enableDialogShadowDOM();
    commentElement.disableDialogShadowDOM();
    commentElement.enableSidebarShadowDOM();
    commentElement.disableSidebarShadowDOM();
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js

  import { VeltCommentBubble } from '@veltdev/react';

  import { useEffect } from 'react'

  export default function YourDocument() {

    return (
      <div>
        <VeltComments
          shadowDom={false}
          dialogShadowDom={false}
          pinShadowDom={false}
          textCommentToolShadowDom={false}
          textCommentToolbarShadowDom={false}
        />


        <VeltCommentBubble shadowDom={false} />
        <VeltCommentTool shadowDom={false} />
        <VeltSidebarButton shadowDom={false} />
        <VeltCommentsSidebar shadowDom={false} />
        <VeltCommentPlayerTimeline shadowDom={false} />     
        <VeltVideoPlayer shadowDom={false} />
        <VeltNotificationsTool shadowDom={false} panelShadowDom={false} />
        <VeltNotificationsPanel shadowDom={false} />

        
      </div>
    )
  }
  ```

  ```html HTML
  <body>
    <velt-comments
      shadow-dom= "false"
      dialog-shadow-dom="false"
      pin-shadow-dom="false"
      text-comment-tool-shadow-dom="false"
      text-comment-toolbar-shadow-dom="false"
    ></velt-comments>

    <velt-comment-bubble shadow-dom="false"></velt-comment-bubble>
    <velt-comment-tool  shadow-dom="false"></velt-comment-tool>
    <velt-sidebar-button  shadow-dom="false"></velt-sidebar-button>
    <velt-comments-sidebar shadow-dom="false"></velt-comments-sidebar>
    <velt-comment-player-timeline shadow-dom="false"></velt-comment-player-timeline>
    <velt-video-player shadow-dom="false"></velt-video-player>
    <velt-notifications-tool shadow-dom="false" panel-shadow-dom="false"></velt-notifications-tool>
    <velt-notifications-panel shadow-dom="false"></velt-notifications-panel>

  </body>
  ```
</RequestExample>


# Themes



## Overview

*   Customize the appearance of all Velt components to match your product's design system.
*   Theme customization works even when Velt's Shadow DOM is enabled, as long as you set the CSS variables on the `<body>` tag.
*   You can customize:
    *   Border radius
    *   Spacing
    *   Typography
    *   Colors for light and dark modes
        *   Base Colors
        *   Accent Colors
        *   Text Shades
        *   Background Shades
        *   Border Shades
        *   Status Colors (error, warning, success)
        *   Transparent colors
*   The following components now support theming (others will be added soon):
    *   Comment Components
    *   Recording Components
    *   Reactions

## Available Theme Variables

<Tabs>
  <Tab title="Border Radius">
    ```css
    --velt-border-radius-2xs: 0.125rem; // 2px
    --velt-border-radius-xs: 0.25rem; // 4px
    --velt-border-radius-sm: 0.5rem; // 8px
    --velt-border-radius-md: 0.75rem; // 12px
    --velt-border-radius-lg: 1rem; // 16px
    --velt-border-radius-xl: 1.25rem; // 20px
    --velt-border-radius-2xl: 1.5rem; // 24px
    --velt-border-radius-3xl: 2rem; // 32px
    --velt-border-radius-full: 5rem; // 80px
    ```
  </Tab>

  <Tab title="Spacing">
    ```css
      --velt-spacing-2xs: 0.125rem; // 2px
      --velt-spacing-xs: 0.25rem; // 4px
      --velt-spacing-sm: 0.5rem; // 8px
      --velt-spacing-md: 0.75rem; // 12px
      --velt-spacing-lg: 1rem; // 16px
      --velt-spacing-xl: 1.25rem; // 20px
      --velt-spacing-2xl: 1.5rem; // 24px
    ```
  </Tab>

  <Tab title="Typography">
    ```css
      --velt-default-font-family: sans-serif;
      --velt-font-size-2xs: 0.625rem; // 10px
      --velt-font-size-xs: 0.75rem; // 12px
      --velt-font-size-sm: 0.875rem; // 14px
      --velt-font-size-md: 1rem; // 16px
      --velt-font-size-lg: 1.5rem; // 24px
      --velt-font-size-xl: 1.75rem; // 28px
      --velt-font-size-2xl: 2rem; // 32px
    ```
  </Tab>

  <Tab title="Colors - Light Mode">
    ```css
      /* Base Colors */
      --velt-light-mode-green: #0DCF82;
      --velt-light-mode-magenta: #A259FE;
      --velt-light-mode-amber: #FF7162;
      --velt-light-mode-purple: #625DF5;
      --velt-light-mode-cyan: #4BC9F0;
      --velt-light-mode-orange: #FE965C;
      --velt-light-mode-black: #080808;
      --velt-light-mode-white: #FFFFFF;
      --velt-light-mode-gray: #EBEBEB;

      /* Accent Colors */
      --velt-light-mode-accent: #625DF5;
      --velt-light-mode-accent-text: #9491F8;
      --velt-light-mode-accent-hover: #534FCF;
      --velt-light-mode-accent-foreground: #FFFFFF;
      --velt-light-mode-accent-light: #F2F2FE;
      --velt-light-mode-accent-transparent: rgba(148, 145, 248, 0.08);

      /* Text Shades */
      --velt-light-mode-text-0: #0A0A0A;
      --velt-light-mode-text-1: #141414;
      --velt-light-mode-text-2: #1F1F1F;
      --velt-light-mode-text-3: #292929;
      --velt-light-mode-text-4: #3D3D3D;
      --velt-light-mode-text-5: #525252;
      --velt-light-mode-text-6: #666666;
      --velt-light-mode-text-7: #7A7A7A;
      --velt-light-mode-text-8: #858585;
      --velt-light-mode-text-9: #999999;
      --velt-light-mode-text-10: #B8B8B8;
      --velt-light-mode-text-11: #A3A3A3;
      --velt-light-mode-text-12: #8F8F8F;

      /* Background Shades */
      --velt-light-mode-background-0: #FFFFFF;
      --velt-light-mode-background-1: #FAFAFA;
      --velt-light-mode-background-2: #F5F5F5;
      --velt-light-mode-background-3: #F0F0F0;
      --velt-light-mode-background-4: #EBEBEB;
      --velt-light-mode-background-5: #E5E5E5;
      --velt-light-mode-background-6: #E0E0E0;
      --velt-light-mode-background-7: #DBDBDB;
      --velt-light-mode-background-8: #D6D6D6;
      --velt-light-mode-background-9: #D1D1D1;
      --velt-light-mode-background-10: #CCCCCC;

      /* Border Shades */
      --velt-light-mode-border-0: #FFFFFF;
      --velt-light-mode-border-1: #FAFAFA;
      --velt-light-mode-border-2: #F5F5F5;
      --velt-light-mode-border-3: #F0F0F0;
      --velt-light-mode-border-4: #EBEBEB;
      --velt-light-mode-border-5: #E5E5E5;
      --velt-light-mode-border-6: #E0E0E0;
      --velt-light-mode-border-7: #DBDBDB;
      --velt-light-mode-border-8: #D6D6D6;
      --velt-light-mode-border-9: #D1D1D1;
      --velt-light-mode-border-10: #CCCCCC;

      /* Status Colors */
      /* Error */
      --velt-light-mode-error: #FF7162;
      --velt-light-mode-error-hover: #DE5041;
      --velt-light-mode-error-foreground: #FFFFFF;
      --velt-light-mode-error-light: #FFF4F2;
      --velt-light-mode-error-transparent: rgba(255, 113, 98, 0.08);

      /* Warning */
      --velt-light-mode-warning: #FFCD2E;
      --velt-light-mode-warning-hover: #C69400;
      --velt-light-mode-warning-foreground: #474747;
      --velt-light-mode-warning-light: #FFFBEE;
      --velt-light-mode-warning-transparent: rgba(255, 205, 46, 0.08);

      /* Success */
      --velt-light-mode-success: #198F65;
      --velt-light-mode-success-hover: #006B41;
      --velt-light-mode-success-foreground: #FFFFFF;
      --velt-light-mode-success-light: #EDF6F3;
      --velt-light-mode-success-transparent: rgba(25, 143, 101, 0.08);

      /* Transparent Colors */
      --velt-light-mode-background-transparent: rgba(255, 255, 255, 0.80);
      --velt-light-mode-border-transparent: rgba(0, 0, 0, 0.16);
      --velt-light-mode-animation-transparent: rgba(255, 255, 255, 0.2);
    ```
  </Tab>

  <Tab title="Colors - Dark Mode">
    ```css
      /* Base Colors */
      --velt-dark-mode-green: #0DCF82;
      --velt-dark-mode-magenta: #A259FE;
      --velt-dark-mode-amber: #FF7162;
      --velt-dark-mode-purple: #625DF5;
      --velt-dark-mode-cyan: #4BC9F0;
      --velt-dark-mode-orange: #FE965C;
      --velt-dark-mode-black: #080808;
      --velt-dark-mode-white: #FFFFFF;
      --velt-dark-mode-gray: #EBEBEB;

      /* Accent Colors */
      --velt-dark-mode-accent: #625DF5;
      --velt-dark-mode-accent-text: #9491F8;
      --velt-dark-mode-accent-hover: #534FCF;
      --velt-dark-mode-accent-foreground: #FFFFFF;
      --velt-dark-mode-accent-light: #F2F2FE;
      --velt-dark-mode-accent-transparent: rgba(148, 145, 248, 0.08);

      /* Text Shades */
      --velt-dark-mode-text-0: #FFFFFF;
      --velt-dark-mode-text-1: #F5F5F5;
      --velt-dark-mode-text-2: #EBEBEB;
      --velt-dark-mode-text-3: #E0E0E0;
      --velt-dark-mode-text-4: #D6D6D6;
      --velt-dark-mode-text-5: #C2C2C2;
      --velt-dark-mode-text-6: #ADADAD;
      --velt-dark-mode-text-7: #8F8F8F;
      --velt-dark-mode-text-8: #7A7A7A;
      --velt-dark-mode-text-9: #666666;
      --velt-dark-mode-text-10: #525252;
      --velt-dark-mode-text-11: #474747;
      --velt-dark-mode-text-12: #3D3D3D;

      /* Background Shades */
      --velt-dark-mode-background-0: #0F0F0F;
      --velt-dark-mode-background-1: #1A1A1A;
      --velt-dark-mode-background-2: #1F1F1F;
      --velt-dark-mode-background-3: #242424;
      --velt-dark-mode-background-4: #292929;
      --velt-dark-mode-background-5: #2E2E2E;
      --velt-dark-mode-background-6: #333333;
      --velt-dark-mode-background-7: #383838;
      --velt-dark-mode-background-8: #3D3D3D;
      --velt-dark-mode-background-9: #424242;
      --velt-dark-mode-background-10: #474747;

      /* Border Shades */
      --velt-dark-mode-border-0: #0F0F0F;
      --velt-dark-mode-border-1: #1A1A1A;
      --velt-dark-mode-border-2: #1F1F1F;
      --velt-dark-mode-border-3: #242424;
      --velt-dark-mode-border-4: #292929;
      --velt-dark-mode-border-5: #2E2E2E;
      --velt-dark-mode-border-6: #333333;
      --velt-dark-mode-border-7: #383838;
      --velt-dark-mode-border-8: #3D3D3D;
      --velt-dark-mode-border-9: #424242;
      --velt-dark-mode-border-10: #474747;

      /* Status Colors */
      /* Error */
      --velt-dark-mode-error: #FF7162;
      --velt-dark-mode-error-hover: #DE5041;
      --velt-dark-mode-error-foreground: #FFFFFF;
      --velt-dark-mode-error-light: #FFF4F2;
      --velt-dark-mode-error-transparent: rgba(255, 113, 98, 0.08);

      /* Warning */
      --velt-dark-mode-warning: #FFCD2E;
      --velt-dark-mode-warning-hover: #C69400;
      --velt-dark-mode-warning-foreground: #474747;
      --velt-dark-mode-warning-light: #FFFBEE;
      --velt-dark-mode-warning-transparent: rgba(255, 205, 46, 0.08);

      /* Success */
      --velt-dark-mode-success: #198F65;
      --velt-dark-mode-success-hover: #006B41;
      --velt-dark-mode-success-foreground: #FFFFFF;
      --velt-dark-mode-success-light: #EDF6F3;
      --velt-dark-mode-success-transparent: rgba(25, 143, 101, 0.08);

      /* Transparent Colors */
      --velt-dark-mode-background-transparent: rgba(0, 0, 0, 0.80);
      --velt-dark-mode-border-transparent: rgba(255, 255, 255, 0.16);
      --velt-dark-mode-animation-transparent: rgba(255, 255, 255, 0.2);
    ```
  </Tab>
</Tabs>

## Example

*   You can update the following variables in `<body>` tag to change the theme.
*   For testing, try copy pasting the following sample themes in body tag:

```css
body {
  --velt-light-mode-accent: #0BA528;
  --velt-light-mode-accent-text: #0BA528;
  --velt-light-mode-accent-hover: #08841F;
  --velt-light-mode-accent-foreground: #FFFFFF;
  --velt-light-mode-accent-light: #DFF9E4;
  --velt-light-mode-accent-transparent: rgba(11, 165, 40, 0.08);

  --velt-dark-mode-accent: #0BA528;
  --velt-dark-mode-accent-text: #0BA528;
  --velt-dark-mode-accent-hover: #08841F;
  --velt-dark-mode-accent-foreground: #FFFFFF;
  --velt-dark-mode-accent-light: #DFF9E4;
  --velt-dark-mode-accent-transparent: rgba(11, 165, 40, 0.08);

  --velt-border-radius-2xs: 2px;
  --velt-border-radius-xs: 2px;
  --velt-border-radius-sm: 2px;
  --velt-border-radius-md: 2px;
  --velt-border-radius-lg: 2px;
  --velt-border-radius-xl: 2px;
  --velt-border-radius-2xl: 2px;
  --velt-border-radius-3xl: 2px;
  --velt-border-radius-full: 2px;
}
```


# Use CSS Library



<Tabs>
  <Tab title="React / Next.js">
    You can use a CSS library such as Tailwind to style the SDK components.

    Simply add the library's classes to the SDK components just like you would to any other component.

    <Warning>To add Custom CSS, ensure that the [Shadow DOM is turned off](./remove-shadow-dom) for the SDK component you are styling.</Warning>

    Conceptual Example:

    ```jsx
    <VeltWireframe>
        <VeltCommentsSidebarWireframe>
            ...
            {/* Header */}
            <VeltCommentsSidebarWireframe.Header>
                <div className="bg-blue-400">
                    <VeltCommentsSidebarWireframe.CloseButton/>
                    <VeltCommentsSidebarWireframe.Search/>
                    <VeltCommentsSidebarWireframe.Status/>
                    <VeltCommentsSidebarWireframe.FilterButton/>
                </div>
            </VeltCommentsSidebarWireframe.Header>
            ...
        </VeltCommentsSidebarWireframe>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    You can use a CSS library such as Tailwind to style the SDK components.

    Simply add the library's classes to the SDK components just like you would to any other component.

    <Warning>To add Custom CSS, ensure that the [Shadow DOM is turned off](./remove-shadow-dom) for the SDK component you are styling.</Warning>

    Conceptual Example:

    ```jsx
    <velt-wireframe style="display:none;">
        <velt-comments-sidebar-wireframe>
            ...
            <!-- Header -->
            <velt-comments-sidebar-header-wireframe class="bg-blue-400">
                <div class="bg-blue-400">
                    <velt-comments-sidebar-close-button-wireframe></velt-comments-sidebar-close-button-wireframe>
                    <velt-comments-sidebar-search-wireframe></velt-comments-sidebar-search-wireframe>
                    <velt-comments-sidebar-status-wireframe></velt-comments-sidebar-status-wireframe>
                    <velt-comments-sidebar-filter-button-wireframe></velt-comments-sidebar-filter-button-wireframe>
                </div>
            </velt-comments-sidebar-header-wireframe>
            ...
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe>
          {/* Skeleton */}
          <VeltCommentsSidebarWireframe.Skeleton />
          <VeltCommentsSidebarWireframe.Panel>
              {/* Header */}
              <VeltCommentsSidebarWireframe.Header>
                  <div className="bg-blue-400">
                      <VeltCommentsSidebarWireframe.CloseButton/>
                      <VeltCommentsSidebarWireframe.Search/>
                      <VeltCommentsSidebarWireframe.Status/>
                      <VeltCommentsSidebarWireframe.FilterButton/>
                  </div>
              </VeltCommentsSidebarWireframe.Header>
              {/* Filter */}
              <VeltCommentsSidebarWireframe.Filter>
                  <VeltCommentsSidebarWireframe.Filter.Title/>
                  <VeltCommentsSidebarWireframe.Filter.CloseButton/>
                  <VeltCommentsSidebarWireframe.Filter.Location/>
                  <VeltCommentsSidebarWireframe.Filter.People/>
                  <VeltCommentsSidebarWireframe.Filter.Category/>
                  <VeltCommentsSidebarWireframe.Filter.Priority/>
                  <VeltCommentsSidebarWireframe.Filter.CommentType/>
                  <VeltCommentsSidebarWireframe.Filter.Versions/>
                  <VeltCommentsSidebarWireframe.Filter.GroupBy/>
                  <VeltCommentsSidebarWireframe.Filter.DoneButton/>
              </VeltCommentsSidebarWireframe.Filter>
              {/* List */}
              <VeltCommentsSidebarWireframe.List/>
              {/* Empty Placeholder */}
              <VeltCommentsSidebarWireframe.EmptyPlaceholder/>
              {/* Page Mode Composer */}
              <VeltCommentsSidebarWireframe.PageModeComposer/>
          <VeltCommentsSidebarWireframe.Panel/>
      </VeltCommentsSidebarWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-wireframe>
          <velt-comment-sidebar-skeleton-wireframe></velt-comment-sidebar-skeleton-wireframe>
          <velt-comment-sidebar-panel-wireframe>
              <!-- Header -->
              <velt-comments-sidebar-header-wireframe>
                  <div class="bg-blue-400">
                      <velt-comments-sidebar-close-button-wireframe></velt-comments-sidebar-close-button-wireframe>
                      <velt-comments-sidebar-search-wireframe></velt-comments-sidebar-search-wireframe>
                      <velt-comments-sidebar-status-wireframe></velt-comments-sidebar-status-wireframe>
                      <velt-comments-sidebar-filter-button-wireframe></velt-comments-sidebar-filter-button-wireframe>
                  </div>
              </velt-comments-sidebar-header-wireframe>
              <!-- Comments Sidebar -->
              <velt-comments-sidebar-filter-wireframe>
                  <velt-comments-sidebar-filter-title-wireframe></velt-comments-sidebar-filter-title-wireframe>
                  <velt-comments-sidebar-filter-close-button-wireframe></velt-comments-sidebar-filter-close-button-wireframe>
                  <velt-comments-sidebar-filter-location-wireframe></velt-comments-sidebar-filter-location-wireframe>
                  <velt-comments-sidebar-filter-people-wireframe></velt-comments-sidebar-filter-people-wireframe>
                  <velt-comments-sidebar-filter-category-wireframe></velt-comments-sidebar-filter-category-wireframe>
                  <velt-comments-sidebar-filter-comment-type-wireframe></velt-comments-sidebar-filter-comment-type-wireframe>
                  <velt-comments-sidebar-filter-priority-wireframe></velt-comments-sidebar-filter-priority-wireframe>
                  <velt-comments-sidebar-filter-versions-wireframe></velt-comments-sidebar-filter-versions-wireframe>
                  <velt-comments-sidebar-filter-group-by-wireframe></velt-comments-sidebar-filter-group-by-wireframe>
                  <velt-comments-sidebar-filter-done-button-wireframe></velt-comments-sidebar-filter-done-button-wireframe>
              </velt-comments-sidebar-filter-wireframe>
              <!-- List -->
              <velt-comments-sidebar-list-wireframe></velt-comments-sidebar-list-wireframe>
              <!-- Empty Placeholder -->
              <velt-comments-sidebar-empty-placeholder-wireframe></velt-comments-sidebar-empty-placeholder-wireframe>
              <!-- Page Mode Composer-->
              <velt-comments-sidebar-page-mode-composer-wireframe></velt-comments-sidebar-page-mode-composer-wireframe>
          </velt-comment-sidebar-panel-wireframe>
      </velt-comments-sidebar-wireframe>
      
  </velt-wireframe>
  ```
</RequestExample>


# Use Custom CSS



<Tabs>
  <Tab title="React / Next.js">
    ## Add Custom CSS

    To add custom CSS to the component, just add CSS into the wireframe template.

    <Warning>To add Custom CSS, ensure that the [Shadow DOM is turned off](./remove-shadow-dom) for the SDK component you are styling.</Warning>

    Conceptual Example:

    ```jsx
    <VeltWireframe>
        <VeltCommentsSidebarWireframe>
            ...
            {/* Header */}
            <VeltCommentsSidebarWireframe.Header>
                <div style={{backgroundColor:'red'}}>
                    <VeltCommentsSidebarWireframe.CloseButton/>
                    <VeltCommentsSidebarWireframe.Search/>
                    <VeltCommentsSidebarWireframe.Status/>
                    <VeltCommentsSidebarWireframe.FilterButton/>
                </div>
            </VeltCommentsSidebarWireframe.Header>
            ...
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ## Add Custom CSS

    To add custom CSS to the component, just add CSS into the wireframe template.

    <Warning>To add Custom CSS, ensure that the [Shadow DOM is turned off](./remove-shadow-dom) for the SDK component you are styling.</Warning>

    Conceptual Example:

    ```jsx
    <velt-wireframe style="display:none;">
        <velt-comments-sidebar-wireframe>
            ...
            <!-- Header -->
            <velt-comments-sidebar-header-wireframe>
                <div style="background-color:'red'">
                    <velt-comments-sidebar-close-button-wireframe></velt-comments-sidebar-close-button-wireframe>
                    <velt-comments-sidebar-search-wireframe></velt-comments-sidebar-search-wireframe>
                    <velt-comments-sidebar-status-wireframe></velt-comments-sidebar-status-wireframe>
                    <velt-comments-sidebar-filter-button-wireframe></velt-comments-sidebar-filter-button-wireframe>
                </div>
            </velt-comments-sidebar-header-wireframe>
            ...
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe>
          {/* Skeleton */}
          <VeltCommentsSidebarWireframe.Skeleton />
          <VeltCommentsSidebarWireframe.Panel>
              {/* Header */}
              <VeltCommentsSidebarWireframe.Header>
                  <div style={{backgroundColor:'red'}}>
                      <VeltCommentsSidebarWireframe.CloseButton/>
                      <VeltCommentsSidebarWireframe.Search/>
                      <VeltCommentsSidebarWireframe.Status/>
                      <VeltCommentsSidebarWireframe.FilterButton/>
                  </div>
              </VeltCommentsSidebarWireframe.Header>
              {/* Filter */}
              <VeltCommentsSidebarWireframe.Filter>
                  <VeltCommentsSidebarWireframe.Filter.Title/>
                  <VeltCommentsSidebarWireframe.Filter.CloseButton/>
                  <VeltCommentsSidebarWireframe.Filter.Location/>
                  <VeltCommentsSidebarWireframe.Filter.People/>
                  <VeltCommentsSidebarWireframe.Filter.Category/>
                  <VeltCommentsSidebarWireframe.Filter.Priority/>
                  <VeltCommentsSidebarWireframe.Filter.CommentType/>
                  <VeltCommentsSidebarWireframe.Filter.Versions/>
                  <VeltCommentsSidebarWireframe.Filter.GroupBy/>
                  <VeltCommentsSidebarWireframe.Filter.DoneButton/>
              </VeltCommentsSidebarWireframe.Filter>
              {/* List */}
              <VeltCommentsSidebarWireframe.List/>
              {/* Empty Placeholder */}
              <VeltCommentsSidebarWireframe.EmptyPlaceholder/>
              {/* Page Mode Composer */}
              <VeltCommentsSidebarWireframe.PageModeComposer/>
          <VeltCommentsSidebarWireframe.Panel/>
      </VeltCommentsSidebarWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-wireframe>
          <velt-comment-sidebar-skeleton-wireframe></velt-comment-sidebar-skeleton-wireframe>
          <velt-comment-sidebar-panel-wireframe>
              <!-- Header -->
              <velt-comments-sidebar-header-wireframe>
                  <div style="background-color:'red'">
                      <velt-comments-sidebar-close-button-wireframe></velt-comments-sidebar-close-button-wireframe>
                      <velt-comments-sidebar-search-wireframe></velt-comments-sidebar-search-wireframe>
                      <velt-comments-sidebar-status-wireframe></velt-comments-sidebar-status-wireframe>
                      <velt-comments-sidebar-filter-button-wireframe></velt-comments-sidebar-filter-button-wireframe>
                  </div>
              </velt-comments-sidebar-header-wireframe>
              <!-- Comments Sidebar -->
              <velt-comments-sidebar-filter-wireframe>
                  <velt-comments-sidebar-filter-title-wireframe></velt-comments-sidebar-filter-title-wireframe>
                  <velt-comments-sidebar-filter-close-button-wireframe></velt-comments-sidebar-filter-close-button-wireframe>
                  <velt-comments-sidebar-filter-location-wireframe></velt-comments-sidebar-filter-location-wireframe>
                  <velt-comments-sidebar-filter-people-wireframe></velt-comments-sidebar-filter-people-wireframe>
                  <velt-comments-sidebar-filter-category-wireframe></velt-comments-sidebar-filter-category-wireframe>
                  <velt-comments-sidebar-filter-comment-type-wireframe></velt-comments-sidebar-filter-comment-type-wireframe>
                  <velt-comments-sidebar-filter-priority-wireframe></velt-comments-sidebar-filter-priority-wireframe>
                  <velt-comments-sidebar-filter-versions-wireframe></velt-comments-sidebar-filter-versions-wireframe>
                  <velt-comments-sidebar-filter-group-by-wireframe></velt-comments-sidebar-filter-group-by-wireframe>
                  <velt-comments-sidebar-filter-done-button-wireframe></velt-comments-sidebar-filter-done-button-wireframe>
              </velt-comments-sidebar-filter-wireframe>
              <!-- List -->
              <velt-comments-sidebar-list-wireframe></velt-comments-sidebar-list-wireframe>
              <!-- Empty Placeholder -->
              <velt-comments-sidebar-empty-placeholder-wireframe></velt-comments-sidebar-empty-placeholder-wireframe>
              <!-- Page Mode Composer-->
              <velt-comments-sidebar-page-mode-composer-wireframe></velt-comments-sidebar-page-mode-composer-wireframe>
          </velt-comment-sidebar-panel-wireframe>
      </velt-comments-sidebar-wireframe>
      
  </velt-wireframe>
  ```
</RequestExample>


# Replace component layout



You can change the default HTML of Velt Components by providing your own HTML as a child of the component.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentDialogWireframe.Composer.ActionButton type="attachments">
            <div className="my-custom-class">
                <MyIcon />
                Attachments
            </div>
        </VeltCommentDialogWireframe.Composer.ActionButton>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comment-dialog-composer-action-button-wireframe type="attachments">
            <div class="my-custom-class">
                <my-icon></my-icon>
                Attachments
            </div>
        </velt-comment-dialog-composer-action-button-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>


# Reorder Components



To modify the order of subcomponents, simply rearrange them within the wireframe template. The rendered component will reflect this new order.

For example, you can change the order of components in the header of a comment dialog.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentDialogWireframe.Header>
            <VeltCommentDialogWireframe.Priority />
            <VeltCommentDialogWireframe.Status />
            <VeltCommentDialogWireframe.CopyLink />
            <VeltCommentDialogWireframe.ResolveButton />
            <VeltCommentDialogWireframe.Options />
        </VeltCommentDialogWireframe.Header>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comment-dialog-header-wireframe>
            <velt-comment-dialog-priority-wireframe></velt-comment-dialog-priority-wireframe>
            <velt-comment-dialog-status-wireframe></velt-comment-dialog-status-wireframe>
            <velt-comment-dialog-copy-link-wireframe></velt-comment-dialog-copy-link-wireframe>
            <velt-comment-dialog-resolve-button-wireframe></velt-comment-dialog-resolve-button-wireframe>
            <velt-comment-dialog-options-wireframe></velt-comment-dialog-options-wireframe>
        </velt-comment-dialog-header-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>


# Overview



You can change the default HTML of Velt Components using two patterns:

<Note> If you modify the component using both the `Standalone` and `Hierarchical` patterns, the `Hierarchical` pattern will override the `Standalone` pattern. </Note>

### Patterns

#### a. Standalone Component Customization (recommended):

*   This pattern lets you modify any Velt Component without the need to include all of its siblings. e.g., Composer submit button, Comment Dialog Header.
*   By focusing on individual components, this approach simplifies the customization process and enhances maintainability.
*   It provides greater flexibility and granular control over specific parts of the UI without needing to write the entire component structure.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentDialogWireframe.Header>
            <div>
                Custom HTML
            </div>
            <VeltCommentDialogWireframe.Status />
            <VeltCommentDialogWireframe.Priority />
            <VeltCommentDialogWireframe.Options />
            <VeltCommentDialogWireframe.CopyLink />
            <VeltCommentDialogWireframe.ResolveButton />
        </VeltCommentDialogWireframe.Header>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comment-dialog-header-wireframe>
            <div>
                Custom HTML
            </div>
            <velt-comment-dialog-status-wireframe></velt-comment-dialog-status-wireframe>
            <velt-comment-dialog-priority-wireframe></velt-comment-dialog-priority-wireframe>
            <velt-comment-dialog-options-wireframe></velt-comment-dialog-options-wireframe>
            <velt-comment-dialog-copy-link-wireframe></velt-comment-dialog-copy-link-wireframe>
            <velt-comment-dialog-resolve-button-wireframe></velt-comment-dialog-resolve-button-wireframe>
        </velt-comment-dialog-header-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

#### b. Hierarchical Component Customization

*   This pattern lets you modify any Velt Component by specifying its entire structure.
*   This approach facilitates easier modifications to multiple sibling components simultaneously, offering a larger control on the component's:
    *   structure and hierarchy.
    *   styling relationships between sibling components.
*   The trade-off is writing more code.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentDialogWireframe>
            {/*  Ghost Banner */}
            <VeltCommentDialogWireframe.GhostBanner />
            {/*  Assignee Banner */}
            <VeltCommentDialogWireframe.AssigneeBanner />
            <div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>  {/*  Increase gap between components */}
                {/*  Header */}
                <VeltCommentDialogWireframe.Header />
                {/* Body */}
                <VeltCommentDialogWireframe.Body />
                {/* Composer */}
                <VeltCommentDialogWireframe.Composer />
            </div>
            {/* All Comments */}
            <VeltCommentDialogWireframe.AllComment />
        </VeltCommentDialogWireframe>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comment-dialog-wireframe>
            <!-- Ghost Banner -->
            <velt-comment-dialog-ghost-banner-wireframe></velt-comment-dialog-ghost-banner-wireframe>
            <!-- Assignee Banner -->
            <velt-comment-dialog-assignee-banner-wireframe></velt-comment-dialog-assignee-banner-wireframe>
            <div style="display: flex; flex-direction: column; gap: 2rem;">  <!--  Increase gap between components -->
                <!-- Header -->
                <velt-comment-dialog-header-wireframe></velt-comment-dialog-header-wireframe>
                <!-- Body -->
                <velt-comment-dialog-body-wireframe></velt-comment-dialog-body-wireframe>
                <!-- Composer -->
                <velt-comment-dialog-composer-wireframe></velt-comment-dialog-composer-wireframe>
            </div>
            <!-- All Comments -->
            <velt-comment-dialog-all-comment-wireframe></velt-comment-dialog-all-comment-wireframe>
        </velt-comment-dialog-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>


# Remove Components



To remove a subcomponent from appearing, simply delete it from the wireframe template.
In this example priority and copy link buttons are removed from the header.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentDialogWireframe.Header>
            <VeltCommentDialogWireframe.Status />
            <VeltCommentDialogWireframe.Options />
            <VeltCommentDialogWireframe.ResolveButton />
        </VeltCommentDialogWireframe.Header>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comment-dialog-header-wireframe>
            <velt-comment-dialog-status-wireframe></velt-comment-dialog-status-wireframe>
            <velt-comment-dialog-options-wireframe></velt-comment-dialog-options-wireframe>
            <velt-comment-dialog-resolve-button-wireframe></velt-comment-dialog-resolve-button-wireframe>
        </velt-comment-dialog-header-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>


# Custom Button



## Custom Arrow Button

If you want to replace the default arrow button with your own custom button, you can pass it in as a child component.

<RequestExample>
  ```js React / Next.js
  import { VeltArrowTool } from '@veltdev/react';

  function YourComponent() {

  return (
      <VeltArrowTool>
          //custom arrow button goes here
          <button className="myButton"></button
      </VeltArrowTool>
    )
    
  }
  ```

  ```html HTML
  <velt-arrow-tool>
      <!-- custom arrow button goes here -->
      <button class="myButton"></button
  </velt-arrow-tool>
  ```
</RequestExample>


# null



<Steps titleSize="h2">
  <Step title="Select the part you want to modify">
    We offer several parts which can be used like classes. Full list below.
    The component is encapsulated in Shadow DOM, which is isolated from the normal DOM.
  </Step>

  <Step title="Apply your CSS rules">
    Set whatever CSS rules you want.
    The part lets you target a specific element within a Shadow DOM.
  </Step>

  <Step title="Check out the table below">
    Reference the table below to see what parts we expose.
    Alternatively, you can directly inspect the component HTML to see what parts are available.

    | property           | description                               |
    | ------------------ | ----------------------------------------- |
    | `container`        | Targets the comment tool container        |
    | `button-container` | Targets the comment tool button container |
    | `button-icon`      | Targets the comment tool button SVG icon  |
  </Step>
</Steps>

<RequestExample>
  ```css Tool
  velt-arrow-tool::part(button-icon) {
    width: 1.5rem;
    height: 1.5rem;
  }
  ```
</RequestExample>


# Slots



<Steps titleSize="h2">
  <Step stepNumber="1" title="Replace the Arrow Tool">
    Provide a template for the Arrow Tool.

    Target the `button` slot with your own custom template.
  </Step>
</Steps>

<RequestExample>
  ```js React / Next.js
  import {
    VeltArrowTool
  } from '@veltdev/react';

  export default function App() {

    return (
      <>

        <VeltArrowTool>
          <button slot="button">Arrow</button>
        </VeltArrowTool>

      </>
    );
  }
  ```

  ```html HTML

  <!doctype html>
  <html lang="en">
    <head>
      <title>Arrow documentation</title>
    </head>
    <body>

      <velt-user-invite-tool>
          <button slot="button">Arrow</button>
      </velt-user-invite-tool>

    </body>
  </html>
  ```
</RequestExample>


# null



To update CSS variables for the Arrow Tool, please refer to [Global Styles](/global-styles/global-styles)


# Overview

This button shows the comment count and the author's avatar. This is used in Popover comments feature.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default comment bubble component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-bubble-light.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentBubbleWireframe>
          <VeltCommentBubbleWireframe.CommentsCount />
          <VeltCommentBubbleWireframe.Avatar />
      </VeltCommentBubbleWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-bubble-wireframe>
          <velt-comment-bubble-comments-count-wireframe></velt-comment-bubble-comments-count-wireframe>
          <velt-comment-bubble-avatar-wireframe></velt-comment-bubble-avatar-wireframe>
      </velt-comment-bubble-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltCommentBubble shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```jsx
    <velt-comment-bubble shadow-dom="false"></velt-comment-bubble>
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-bubble-1.png)

By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

`Default: false`

Below are examples to enable dark mode for comment bubble component.

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```js
    <VeltCommentBubble darkMode={true} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```HTML
    <velt-comment-bubble dark-mode="true"></velt-comment-bubble>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# null

The subcomponent on the Comment Bubble that shows the User avatar

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-bubble-sub-2.png)

<Note>This subcomponent does not support children</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentBubbleWireframe.Avatar />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-bubble-avatar-wireframe></velt-comment-bubble-avatar-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Comment Bubble that shows the number of Comments made on a thread.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-bubble-sub-1.png)

<Note>This subcomponent does not support children</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentBubbleWireframe.CommentsCount />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-bubble-comments-count-wireframe></velt-comment-bubble-comments-count-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The interface that appears when you try to read an existing Comment or make a new Comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default comment dialog component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-1.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-2.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe>
          {/*  Ghost Banner - Only shown for ghost comments */}
          <VeltCommentDialogWireframe.GhostBanner />
          {/*  Private Banner - Only shown for private comments */}
          <VeltCommentDialogWireframe.PrivateBanner />
          {/*  Assignee Banner - Only shown for assigned comments */}
          <VeltCommentDialogWireframe.AssigneeBanner />
          {/*  Header */}
          <VeltCommentDialogWireframe.Header />
          {/* Private Badge - Only shown for private comments */}
          <VeltCommentDialogWireframe.PrivateBadge />
          {/* Body */}
          <VeltCommentDialogWireframe.Body />
          {/* Composer */}
          <VeltCommentDialogWireframe.Composer />
          {/* All Comments */}
          <VeltCommentDialogWireframe.AllComment />
          {/* Approve - Only when moderator mode is on */}
          <VeltCommentDialogWireframe.Approve />
          {/* Sign In - Only when user is anonymous and sign in button is enabled */}
          <VeltCommentDialogWireframe.SignIn />
          {/* Upgrade - Not visible by default */}
          <VeltCommentDialogWireframe.Upgrade />
          {/* Suggestion Action - Only when suggestion mode is on */}
          <VeltCommentDialogWireframe.SuggestionAction />
      </VeltCommentDialogWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-wireframe>
          <!-- Ghost Banner - Only shown for ghost comments -->
          <velt-comment-dialog-ghost-banner-wireframe></velt-comment-dialog-ghost-banner-wireframe>
          <!-- Private Banner - Only shown for private comments -->
          <velt-comment-dialog-private-banner-wireframe></velt-comment-dialog-private-banner-wireframe>
          <!-- Assignee Banner - Only shown for assigned comments -->
          <velt-comment-dialog-assignee-banner-wireframe></velt-comment-dialog-assignee-banner-wireframe>
          <!-- Header -->
          <velt-comment-dialog-header-wireframe></velt-comment-dialog-header-wireframe>
          <!-- Private Badge - Only shown for private comments -->
          <velt-comment-dialog-private-badge-wireframe></velt-comment-dialog-private-badge-wireframe>
          <!-- Body -->
          <velt-comment-dialog-body-wireframe></velt-comment-dialog-body-wireframe>
          <!-- Composer -->
          <velt-comment-dialog-composer-wireframe></velt-comment-dialog-composer-wireframe>
          <!-- All Comments -->
          <velt-comment-dialog-all-comment-wireframe></velt-comment-dialog-all-comment-wireframe>
          <!-- Approve - Only when moderator mode is on -->
          <velt-comment-dialog-approve-wireframe></velt-comment-dialog-approve-wireframe>
          <!-- Sign In - Only when user is anonymous and sign in button is enabled -->
          <velt-comment-dialog-sign-in-wireframe></velt-comment-dialog-sign-in-wireframe>
          <!-- Upgrade - Not visible by default -->
          <velt-comment-dialog-upgrade-wireframe></velt-comment-dialog-upgrade-wireframe>
          <!-- Suggestion Action - Only when suggestion mode is on -->
          <velt-comment-dialog-suggestion-action-wireframe></velt-comment-dialog-suggestion-action-wireframe>
      </velt-comment-dialog-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Variants



## Pre-defined Variants

The Comment Dialog has 2 pre-defined variants:

*   `dialog`: this will customize the Comment Dialog only within Pin, Area, and Text Comments
*   `sidebar`: this will customize the Comment Dialog only within Sidebar comments

To use them, set the `variant` name in the wireframe template equal to one of the pre-defined variants. You do not need to add it to the actual Velt component.

<RequestExample>
  ```jsx React / Next.js
   <VeltWireframe>
      {/* This pre-defined variant will change the appearance of the Comment Dialog within Pin, Area, and Text comments only */}
      <VeltCommentDialogWireframe variant="dialog">
          ...
      </VeltCommentDialogWireframe>

      {/* This pre-defined variant will change the appearance of the Comment Dialog within the Sidebar only */}
      <VeltCommentDialogWireframe variant="sidebar">
          ...
      </VeltCommentDialogWireframe>

      {/* If you dont use any variants, then customization will be applied to the Comment Dialog globally */}
      <VeltCommentDialogWireframe>
          ...
      </VeltCommentDialogWireframe>
  </VeltWireframe>
  ```

  ```jsx HTML
  <velt-wireframe style="display:none;">
  <!-- This pre-defined variant will change the appearance of the Comment Dialog within Pin, Area, and Text comments only -->
      <velt-comment-dialog-wireframe variant="dialog">
          <velt-comment-dialog-body-wireframe></velt-comment-dialog-body-wireframe>
          <velt-comment-dialog-composer-wireframe></velt-comment-dialog-composer-wireframe>
          <velt-comment-dialog-header-wireframe></velt-comment-dialog-header-wireframe>
      </velt-comment-dialog-wireframe>

      <!-- This pre-defined variant will change the appearance of the Comment Dialog within the Sidebar only -->
      <velt-comment-dialog-wireframe variant="sidebar">
          <velt-comment-dialog-body-wireframe></velt-comment-dialog-body-wireframe>
          <velt-comement-dialog-composer-wireframe></velt-comement-dialog-composer-wireframe>
          <velt-comment-dialog-header-wireframe></velt-comment-dialog-header-wireframe>
      </velt-comment-dialog-wireframe>

      <!--  If you dont use any variants, then customization will be applied to the Comment Dialog globally -->
      <velt-comment-dialog-wireframe>
          <velt-comment-dialog-body-wireframe></velt-comment-dialog-body-wireframe>
          <velt-comement-dialog-composer-wireframe></velt-comement-dialog-composer-wireframe>
          <velt-comment-dialog-header-wireframe></velt-comment-dialog-header-wireframe>
      </velt-comment-dialog-wireframe>

  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltComments dialogShadowDom={false} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDialogShadowDOM();
    commentElement.disableDialogShadowDOM();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```
    <velt-comments dialog-shadow-dom="false"></velt-comments>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDialogShadowDOM();
    commentElement.disableDialogShadowDOM();
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/dark-light-mode.png)

By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

`Default: false`

Below are the examples to enable Dark Mode for comments dialog:

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```js
    <VeltComments dialogDarkMode={true}/>
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```js
    <velt-comments dialog-dark-mode="true"></velt-comments>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# null

The subcomponent of the Comment Dialog that is used to show the All Comments button that opens the Comments Sidebar

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any of the components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-8.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.AllComment />
  </VeltWireframe>
  ```

  ```HTML HTML 
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-all-comment-wireframe></velt-comment-dialog-all-comment-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that is used approve Comments in Moderator Mode

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-9.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Approve />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-approve-wireframe></velt-comment-dialog-approve-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that is used assign a Comment as a task

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-3.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentDialogWireframe.AssigneeBanner.UserAvatar`
    *   `VeltCommentDialogWireframe.AssigneeBanner.UserName`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-comment-dialog-assignee-banner-user-avatar-wireframe`
    *   `velt-comment-dialog-assignee-banner-user-name-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx "React / Next.js"
  <VeltWireframe>
      <VeltCommentDialogWireframe.AssigneeBanner>
          <VeltCommentDialogWireframe.AssigneeBanner.ResolveButton />
          <VeltCommentDialogWireframe.AssigneeBanner.UserAvatar />
          <VeltCommentDialogWireframe.AssigneeBanner.UserName />
      </VeltCommentDialogWireframe.AssigneeBanner>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-assignee-banner-wireframe>
          <velt-comment-dialog-assignee-banner-user-avatar-wireframe></velt-comment-dialog-assignee-banner-user-avatar-wireframe>
          <velt-comment-dialog-assignee-banner-user-name-wireframe></velt-comment-dialog-assignee-banner-user-name-wireframe>
          <velt-comment-dialog-assignee-banner-resolve-button-wireframe></velt-comment-dialog-assignee-banner-resolve-button-wireframe>
      </velt-comment-dialog-assignee-banner-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the tooltip that appears when you hover over an Autocomplete Chip.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/autocomplete-chip-tooltip.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltAutocompleteChipTooltipWireframe>
          <VeltAutocompleteChipTooltipWireframe.Icon />
          <VeltAutocompleteChipTooltipWireframe.Name />
          <VeltAutocompleteChipTooltipWireframe.Description />
      </VeltAutocompleteChipTooltipWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-autocomplete-chip-tooltip-wireframe>
          <velt-autocomplete-chip-tooltip-icon-wireframe></velt-autocomplete-chip-tooltip-icon-wireframe>
          <velt-autocomplete-chip-tooltip-name-wireframe></velt-autocomplete-chip-tooltip-name-wireframe>
          <velt-autocomplete-chip-tooltip-description-wireframe></velt-autocomplete-chip-tooltip-description-wireframe>
      </velt-autocomplete-chip-tooltip-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the dropdown list that appears when you press an Autocomplete hotkey.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-user-selector-dropdown-1.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-user-selector-dropdown-2.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltAutocompleteOptionWireframe>
          <VeltAutocompleteOptionWireframe.Icon />
          <VeltAutocompleteOptionWireframe.Name />
          <VeltAutocompleteOptionWireframe.Description field='name' />
          <VeltAutocompleteOptionWireframe.ErrorIcon />
      </VeltAutocompleteOptionWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-autocomplete-option-wireframe>
          <velt-autocomplete-option-icon-wireframe></velt-autocomplete-option-icon-wireframe>
          <velt-autocomplete-option-name-wireframe></velt-autocomplete-option-name-wireframe>
          <velt-autocomplete-option-description-wireframe field="name"></velt-autocomplete-option-description-wireframe>
          <velt-autocomplete-option-error-icon-wireframe></velt-autocomplete-option-error-icon-wireframe>
      <velt-autocomplete-option-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The subcomponent of the Comment Dialog that is used to show all Comment Replies as well as the Comment Composer.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-6.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Body>
          <VeltCommentDialogWireframe.Threads>
              <VeltCommentDialogWireframe.ThreadCard />
              <VeltCommentDialogWireframe.MoreReply />
          </VeltCommentDialogWireframe.Threads>
          <VeltCommentDialogWireframe.ToggleReply />
      </VeltCommentDialogWireframe.Body>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-wireframe>
          ...
          <velt-comment-dialog-body-wireframe>
              <velt-comment-dialog-threads-wireframe>
                  <velt-comment-dialog-thread-card-wireframe></velt-comment-dialog-thread-card-wireframe>
                  <velt-comment-dialog-more-reply-wireframe></velt-comment-dialog-more-reply-wireframe>
              </velt-comment-dialog-threads-wireframe>
              <velt-comment-dialog-toggle-reply-wireframe></velt-comment-dialog-toggle-reply-wireframe>
          </velt-comment-dialog-body-wireframe>
          ...
      </velt-comment-dialog-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# ThreadCard

The subcomponent of the Body of the Comment Dialog that is used to show attachments added to a Comment reply.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/threadcard-attachments.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentDialogWireframe.ThreadCard.Avatar`
    *   `VeltCommentDialogWireframe.ThreadCard.DeviceType`
    *   `VeltCommentDialogWireframe.ThreadCard.Name`
    *   `VeltCommentDialogWireframe.ThreadCard.Time`
    *   `VeltCommentDialogWireframe.ThreadCard.Message`
    *   `VeltCommentDialogWireframe.ThreadCard.ReactionTool`
    *   `VeltCommentDialogWireframe.ThreadCard.Reactions`
    *   `VeltCommentDialogWireframe.ThreadCard.Recordings`
  </Tab>

  <Tab title="Other Frameworks">
    ## Subcomponents that don't support children

    *   `velt-comment-dialog-thread-card-avatar-wireframe`
    *   `velt-comment-dialog-thread-card-device-type-wireframe>`
    *   `velt-comment-dialog-thread-card-name-wireframe`
    *   `velt-comment-dialog-thread-card-time-wireframe`
    *   `velt-comment-dialog-thread-card-message-wireframe`
    *   `velt-comment-dialog-thread-card-reaction-tool-wireframe`
    *   `velt-comment-dialog-thread-card-reactions-wireframe`
    *   `velt-comment-dialog-thread-card-recordings-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.ThreadCard>
          <VeltCommentDialogWireframe.ThreadCard.Avatar />
          <VeltCommentDialogWireframe.ThreadCard.Name />
          <VeltCommentDialogWireframe.ThreadCard.Unread /> {/* Unread indicator */}
          <VeltCommentDialogWireframe.ThreadCard.SeenDropdown /> {/* Seen indicator with dropdown */}
          <VeltCommentDialogWireframe.ThreadCard.Draft /> {/* Draft indicator */}
          <VeltCommentDialogWireframe.ThreadCard.Time />
          <VeltCommentDialogWireframe.ThreadCard.DeviceType />
          <VeltCommentDialogWireframe.ThreadCard.Options />
          <VeltCommentDialogWireframe.ThreadCard.Message />
          <VeltCommentDialogWireframe.ThreadCard.ReactionTool />
          <VeltCommentDialogWireframe.ThreadCard.Reactions />
          <VeltCommentDialogWireframe.ThreadCard.Attachments>
              ... customizable
          </VeltCommentDialogWireframe.ThreadCard.Attachments>    
          <VeltCommentDialogWireframe.ThreadCard.Recordings />
      </VeltCommentDialogWireframe.ThreadCard>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-thread-card-wireframe>
          <velt-comment-dialog-thread-card-avatar-wireframe></velt-comment-dialog-thread-card-avatar-wireframe>
          <velt-comment-dialog-thread-card-name-wireframe></velt-comment-dialog-thread-card-name-wireframe>
          <velt-comment-dialog-thread-card-unread-wireframe></velt-comment-dialog-thread-card-unread-wireframe> <!-- Unread indicator -->
          <velt-comment-dialog-thread-card-seen-dropdown-wireframe></velt-comment-dialog-thread-card-seen-dropdown-wireframe> <!-- Seen indicator with dropdown -->
          <velt-comment-dialog-thread-card-draft-wireframe></velt-comment-dialog-thread-card-draft-wireframe> <!-- Draft indicator -->
          <velt-comment-dialog-thread-card-time-wireframe></velt-comment-dialog-thread-card-time-wireframe>
          <velt-comment-dialog-thread-card-device-type-wireframe></velt-comment-dialog-thread-card-device-type-wireframe>
          <velt-comment-dialog-thread-card-options-wireframe></velt-comment-dialog-thread-card-options-wireframe>
          <velt-comment-dialog-thread-card-message-wireframe></velt-comment-dialog-thread-card-message-wireframe>
          <velt-comment-dialog-thread-card-reaction-tool-wireframe></velt-comment-dialog-thread-card-reaction-tool-wireframe>
          <velt-comment-dialog-thread-card-reactions-wireframe></velt-comment-dialog-thread-card-reactions-wireframe>
          <velt-comment-dialog-thread-card-attachments-wireframe>
              ... customizable
          </velt-comment-dialog-thread-card-attachments-wireframe>
          <velt-comment-dialog-thread-card-recordings-wireframe></velt-comment-dialog-thread-card-recordings-wireframe>
      </velt-comment-dialog-thread-card-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# ThreadCard Attachments

The subcomponent of the Body of the Comment Dialog that is used to show attachments added to a Comment reply.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/threadcard-attachments.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentDialogWireframe.ThreadCard.Attachments.Image.Preview`
    *   `VeltCommentDialogWireframe.ThreadCard.Attachments.Other.Name`
    *   `VeltCommentDialogWireframe.ThreadCard.Attachments.Other.Size`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-comment-dialog-thread-card-attachments-image-preview-wireframe`
    *   `velt-comment-dialog-thread-card-attachments-other-name-wireframe`
    *   `velt-comment-dialog-thread-card-attachments-other-size-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.ThreadCard.Attachments>
          <VeltCommentDialogWireframe.ThreadCard.Attachments.Image>
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Image.Preview />
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Image.Download />
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Image.Delete />
          </VeltCommentDialogWireframe.ThreadCard.Attachments.Image>
          <VeltCommentDialogWireframe.ThreadCard.Attachments.Other>
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Other.Icon />
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Other.Name />
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Other.Size />
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Other.Download />
              <VeltCommentDialogWireframe.ThreadCard.Attachments.Other.Delete />
          </VeltCommentDialogWireframe.ThreadCard.Attachments.Other>                                     
      </VeltCommentDialogWireframe.ThreadCard.Attachments>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-thread-card-attachments-wireframe>
          <velt-comment-dialog-thread-card-attachments-image-wireframe>
              <velt-comment-dialog-thread-card-attachments-image-preview-wireframe></velt-comment-dialog-thread-card-attachments-image-preview-wireframe>
              <velt-comment-dialog-thread-card-attachments-image-download-wireframe></velt-comment-dialog-thread-card-attachments-image-download-wireframe>
              <velt-comment-dialog-thread-card-attachments-image-delete-wireframe></velt-comment-dialog-thread-card-attachments-image-delete-wireframe>
          </velt-comment-dialog-thread-card-attachments-image-wireframe>
          <velt-comment-dialog-thread-card-attachments-other-wireframe>
              <velt-comment-dialog-thread-card-attachments-other-icon-wireframe></velt-comment-dialog-thread-card-attachments-other-icon-wireframe>
              <velt-comment-dialog-thread-card-attachments-other-name-wireframe></velt-comment-dialog-thread-card-attachments-other-name-wireframe>
              <velt-comment-dialog-thread-card-attachments-other-size-wireframe></velt-comment-dialog-thread-card-attachments-other-size-wireframe>
              <velt-comment-dialog-thread-card-attachments-other-download-wireframe></velt-comment-dialog-thread-card-attachments-other-download-wireframe>
              <velt-comment-dialog-thread-card-attachments-other-delete-wireframe></velt-comment-dialog-thread-card-attachments-other-delete-wireframe>
          </velt-comment-dialog-thread-card-attachments-other-wireframe>
      </velt-comment-dialog-thread-card-attachments-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# ThreadCard Options

The subcomponent of the Body of the Comment Dialog that is used to show the options dropdown

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/threadcard-options.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.ThreadCard.Options>
          <VeltCommentDialogWireframe.ThreadCard.Options.Trigger />
          <VeltCommentDialogWireframe.ThreadCard.Options.Content>
              <VeltCommentDialogWireframe.ThreadCard.Options.Content.MakePrivate>
                  <VeltCommentDialogWireframe.ThreadCard.Options.Content.MakePrivate.Enable />
                  <VeltCommentDialogWireframe.ThreadCard.Options.Content.MakePrivate.Disable />
              </VeltCommentDialogWireframe.ThreadCard.Options.Content.MakePrivate>
              <VeltCommentDialogWireframe.ThreadCard.Options.Content.Assign />
              <VeltCommentDialogWireframe.ThreadCard.Options.Content.Edit />
              <VeltCommentDialogWireframe.ThreadCard.Options.Content.Delete>
                  <VeltCommentDialogWireframe.ThreadCard.Options.Content.Delete.Thread />
                  <VeltCommentDialogWireframe.ThreadCard.Options.Content.Delete.Comment />
              </VeltCommentDialogWireframe.ThreadCard.Options.Content.Delete>
          </VeltCommentDialogWireframe.ThreadCard.Options.Content>
      </VeltCommentDialogWireframe.ThreadCard.Options>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
     <velt-comment-dialog-thread-card-options-wireframe>
         <velt-comment-dialog-options-dropdown-trigger-wireframe></velt-comment-dialog-options-dropdown-trigger-wireframe>
         <velt-comment-dialog-options-dropdown-content-wireframe>
             <velt-comment-dialog-options-dropdown-content-make-private-wireframe>
                 <velt-comment-dialog-options-dropdown-content-make-private-enable-wireframe></velt-comment-dialog-options-dropdown-content-make-private-enable-wireframe>
                 <velt-comment-dialog-options-dropdown-content-make-private-disable-wireframe></velt-comment-dialog-options-dropdown-content-make-private-disable-wireframe>
             </velt-comment-dialog-options-dropdown-content-make-private-wireframe>
             <velt-comment-dialog-options-dropdown-content-assign-wireframe></velt-comment-dialog-options-dropdown-content-assign-wireframe>
             <velt-comment-dialog-options-dropdown-content-edit-wireframe></velt-comment-dialog-options-dropdown-content-edit-wireframe>
             <velt-comment-dialog-options-dropdown-content-delete-wireframe>
                 <velt-comment-dialog-options-dropdown-content-delete-thread-wireframe></velt-comment-dialog-options-dropdown-content-delete-thread-wireframe>
                 <velt-comment-dialog-options-dropdown-content-delete-comment-wireframe></velt-comment-dialog-options-dropdown-content-delete-comment-wireframe>
             </velt-comment-dialog-options-dropdown-content-delete-wireframe>
         </velt-comment-dialog-options-dropdown-content-wireframe>
     </velt-comment-dialog-thread-card-options-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# ThreadCard Seen



<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<Frame>
  ![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/seen-feature.png)
</Frame>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.ThreadCard.SeenDropdown>
          <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Trigger />
          <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content>
              <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Title />
              <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Items>
                  <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Items.Item>
                      <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Items.Item.Time />
                      <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Items.Item.Name />
                      <VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Items.Item.Avatar />
                  </VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Items.Item>
              </VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content.Items>
          </VeltCommentDialogWireframe.ThreadCard.SeenDropdown.Content>
      </VeltCommentDialogWireframe.ThreadCard.SeenDropdown>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
     <velt-comment-dialog-thread-card-seen-dropdown-wireframe>
        <velt-comment-dialog-thread-card-seen-dropdown-trigger-wireframe></velt-comment-dialog-thread-card-seen-dropdown-trigger-wireframe>
        <velt-comment-dialog-thread-card-seen-dropdown-content-wireframe>
           <velt-comment-dialog-thread-card-seen-dropdown-content-title-wireframe></velt-comment-dialog-thread-card-seen-dropdown-content-title-wireframe>
           <velt-comment-dialog-thread-card-seen-dropdown-content-items-wireframe>
              <velt-comment-dialog-thread-card-seen-dropdown-content-item-wireframe>
                 <velt-comment-dialog-thread-card-seen-dropdown-content-item-avatar-wireframe></velt-comment-dialog-thread-card-seen-dropdown-content-item-avatar-wireframe>
                 <velt-comment-dialog-thread-card-seen-dropdown-content-item-name-wireframe></velt-comment-dialog-thread-card-seen-dropdown-content-item-name-wireframe>
                 <velt-comment-dialog-thread-card-seen-dropdown-content-item-time-wireframe></velt-comment-dialog-thread-card-seen-dropdown-content-item-time-wireframe>
              </velt-comment-dialog-thread-card-seen-dropdown-content-item-wireframe>
           </velt-comment-dialog-thread-card-seen-dropdown-content-items-wireframe>
        </velt-comment-dialog-thread-card-seen-dropdown-content-wireframe>
     </velt-comment-dialog-thread-card-seen-dropdown-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The subcomponent of the Comment Dialog that is used to compose new Comment replies.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<Note>
  When the composer is in focus, a dynamic CSS class `velt-composer-focused` is added to the composer container.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-7.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentDialogWireframe.Composer.Recordings`
    *   `VeltCommentDialogWireframe.Composer.Input`
    *   `VeltCommentDialogWireframe.Composer.AssignUser`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-comment-dialog-composer-recordings-wireframe`
    *   `velt-comment-dialog-composer-input-wireframe`
    *   `velt-comment-dialog-composer-assign-user-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Composer>
          <VeltCommentDialogWireframe.Composer.PrivateBadge />
          <VeltCommentDialogWireframe.Composer.Avatar /> {/* used for inline comments */}
          <VeltCommentDialogWireframe.Composer.Attachments>
              ... customizable
          </VeltCommentDialogWireframe.Composer.Attachments>
          <VeltCommentDialogWireframe.Composer.Recordings />
          <VeltCommentDialogWireframe.Composer.Input />
          <VeltCommentDialogWireframe.Composer.ActionButton type="userMentions" />
          <VeltCommentDialogWireframe.Composer.ActionButton type="attachments" />
          <VeltCommentDialogWireframe.Composer.ActionButton type="audio" />
          <VeltCommentDialogWireframe.Composer.ActionButton type="video" />
          <VeltCommentDialogWireframe.Composer.ActionButton type="screen" />
          <VeltCommentDialogWireframe.Composer.ActionButton type="submit" />
          <VeltCommentDialogWireframe.Composer.AssignUser />
          <VeltCommentDialogWireframe.Composer.Input placeholder='Custom Placeholder' />
      </VeltCommentDialogWireframe.Composer>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-composer-wireframe>
          <velt-comment-dialog-composer-private-badge-wireframe></velt-comment-dialog-composer-private-badge-wireframe>
          <velt-comment-dialog-composer-avatar-wireframe></velt-comment-dialog-composer-avatar-wireframe> <!-- Used for inline comments-->
          <velt-comment-dialog-composer-attachments-wireframe>
              ... customizable 
          </velt-comment-dialog-composer-attachments-wireframe>
          <velt-comment-dialog-composer-recordings-wireframe></velt-comment-dialog-composer-recordings-wireframe>
          <velt-comment-dialog-composer-input-wireframe></velt-comment-dialog-composer-input-wireframe>
          <velt-comment-dialog-composer-action-button-wireframe type="userMentions"></velt-comment-dialog-composer-action-button-wireframe>
          <velt-comment-dialog-composer-action-button-wireframe type="attachments"></velt-comment-dialog-composer-action-button-wireframe>
          <velt-comment-dialog-composer-action-button-wireframe type="audio"></velt-comment-dialog-composer-action-button-wireframe>
          <velt-comment-dialog-composer-action-button-wireframe type="video"></velt-comment-dialog-composer-action-button-wireframe>
          <velt-comment-dialog-composer-action-button-wireframe type="screen"></velt-comment-dialog-composer-action-button-wireframe>
          <velt-comment-dialog-composer-action-button-wireframe type="submit"></velt-comment-dialog-composer-action-button-wireframe>
          <velt-comment-dialog-composer-assign-user-wireframe></velt-comment-dialog-composer-assign-user-wireframe>
          <velt-comment-dialog-composer-input-wireframe placeholder="Custom Placeholder"></velt-comment-dialog-composer-input-wireframe>
      </velt-comment-dialog-composer-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Composer Attachments

The subcomponent of the Comoposer of the Comment Dialog that is used to show attachments on a Comment that has been composed but hasn't been sent yet.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/composer-attachments.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentDialogWireframe.Composer.Attachments.Selected.Image.Preview`
    *   `VeltCommentDialogWireframe.Composer.Attachments.Selected.Other.Name`
    *   `VeltCommentDialogWireframe.Composer.Attachments.Selected.Other.Size`
    *   `VeltCommentDialogWireframe.Composer.Attachments.Invalid.Item.Preview`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-comment-dialog-composer-attachments-image-preview-wireframe`
    *   `velt-comment-dialog-composer-attachments-other-name-wireframe`
    *   `velt-comment-dialog-composer-attachments-other-size-wireframe`
    *   `velt-comment-dialog-composer-attachments-invalid-item-preview-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Composer.Attachments>
          <VeltCommentDialogWireframe.Composer.Attachments.Selected>
              <VeltCommentDialogWireframe.Composer.Attachments.Selected.Image>
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Image.Preview />
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Image.Loading />
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Image.Delete />
              </VeltCommentDialogWireframe.Composer.Attachments.Selected.Image>
              <VeltCommentDialogWireframe.Composer.Attachments.Selected.Other>
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Other.Icon />
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Other.Name />
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Other.Size />
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Other.Loading />
                  <VeltCommentDialogWireframe.Composer.Attachments.Selected.Other.Delete />
              </VeltCommentDialogWireframe.Composer.Attachments.Selected.Other>
          </VeltCommentDialogWireframe.Composer.Attachments.Selected>
          <VeltCommentDialogWireframe.Composer.Attachments.Invalid>
              <VeltCommentDialogWireframe.Composer.Attachments.Invalid.Item>
                  <VeltCommentDialogWireframe.Composer.Attachments.Invalid.Item.Preview />
                  <VeltCommentDialogWireframe.Composer.Attachments.Invalid.Item.Message />
                  <VeltCommentDialogWireframe.Composer.Attachments.Invalid.Item.Delete />
              </VeltCommentDialogWireframe.Composer.Attachments.Invalid.Item>
          </VeltCommentDialogWireframe.Composer.Attachments.Invalid>
      </VeltCommentDialogWireframe.Composer.Attachments>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-composer-attachments-wireframe>
          <velt-comment-dialog-composer-attachments-selected-wireframe>
              <velt-comment-dialog-composer-attachments-image-wireframe>
                  <velt-comment-dialog-composer-attachments-image-preview-wireframe></velt-comment-dialog-composer-attachments-image-preview-wireframe>
                  <velt-comment-dialog-composer-attachments-image-loading-wireframe></velt-comment-dialog-composer-attachments-image-loading-wireframe>
                  <velt-comment-dialog-composer-attachments-image-delete-wireframe></velt-comment-dialog-composer-attachments-image-delete-wireframe>
              </velt-comment-dialog-composer-attachments-image-wireframe>
              <velt-comment-dialog-composer-attachments-other-wireframe>
                  <velt-comment-dialog-composer-attachments-other-icon-wireframe></velt-comment-dialog-composer-attachments-other-icon-wireframe>
                  <velt-comment-dialog-composer-attachments-other-name-wireframe></velt-comment-dialog-composer-attachments-other-name-wireframe>
                  <velt-comment-dialog-composer-attachments-other-size-wireframe></velt-comment-dialog-composer-attachments-other-size-wireframe>
                  <velt-comment-dialog-composer-attachments-other-loading-wireframe></velt-comment-dialog-composer-attachments-other-loading-wireframe>
                  <velt-comment-dialog-composer-attachments-other-delete-wireframe></velt-comment-dialog-composer-attachments-other-delete-wireframe>
              </velt-comment-dialog-composer-attachments-other-wireframe>
          </velt-comment-dialog-composer-attachments-selected-wireframe>
          <velt-comment-dialog-composer-attachments-invalid-wireframe>
              <velt-comment-dialog-composer-attachments-invalid-item-wireframe>
                  <velt-comment-dialog-composer-attachments-invalid-item-preview-wireframe></velt-comment-dialog-composer-attachments-invalid-item-preview-wireframe>
                      <velt-comment-dialog-composer-attachments-invalid-item-message-wireframe></velt-comment-dialog-composer-attachments-invalid-item-message-wireframe>
                      <velt-comment-dialog-composer-attachments-invalid-item-delete-wireframe></velt-comment-dialog-composer-attachments-invalid-item-delete-wireframe>
                  </velt-comment-dialog-composer-attachments-invalid-item-wireframe>
              </velt-comment-dialog-composer-attachments-invalid-wireframe>
         </velt-comment-dialog-composer-attachments-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that is shown in the Composer when Private Mode is turned on.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-5.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Composer.PrivateBadge />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-composer-private-badge-wireframe></velt-comment-dialog-composer-private-badge-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Custom Annotation Dropdown

The subcomponent of the Comment Dialog that represents the custom annotation dropdown.

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/comments-dialog-annotation.png)
![](https://mintlify.s3-us-west-1.amazonaws.com/velt/gifs/comments-dialog-annotation-breakdown.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltCommentDialogWireframe.CustomAnnotationDropdown>
      <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger>
          <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.List>
              <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.RemainingCount></VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.RemainingCount>
              
              <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Placeholder>
                  Select a category
              </VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Placeholder>
              
              <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Arrow></VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.Arrow>
              <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.List.Item>
                  <VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.List.Item></VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.List.Item>
              </VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.List.Item>
          </VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger.List>
      </VeltCommentDialogWireframe.CustomAnnotationDropdown.Trigger>
      <VeltCommentDialogWireframe.CustomAnnotationDropdown.Content>
          <VeltCommentDialogWireframe.CustomAnnotationDropdown.Content.Item>
              <VeltCommentDialogWireframe.CustomAnnotationDropdown.Content.Item.Label></VeltCommentDialogWireframe.CustomAnnotationDropdown.Content.Item.Label>
              <VeltCommentDialogWireframe.CustomAnnotationDropdown.Content.Item.Icon></VeltCommentDialogWireframe.CustomAnnotationDropdown.Content.Item.Icon>
          </VeltCommentDialogWireframe.CustomAnnotationDropdown.Content.Item>
      </VeltCommentDialogWireframe.CustomAnnotationDropdown.Content>
  </VeltCommentDialogWireframe.CustomAnnotationDropdown>
  ```

  ```HTML HTML 
   <velt-comment-dialog-custom-annotation-dropdown-wireframe>
      <velt-comment-dialog-custom-annotation-dropdown-trigger-wireframe>
          <velt-comment-dialog-custom-annotation-dropdown-trigger-list-wireframe>
              <velt-comment-dialog-custom-annotation-dropdown-trigger-list-item-wireframe></velt-comment-dialog-custom-annotation-dropdown-trigger-list-item-wireframe>
          </velt-comment-dialog-custom-annotation-dropdown-trigger-list-wireframe>
          <velt-comment-dialog-custom-annotation-dropdown-trigger-remaining-count-wireframe></velt-comment-dialog-custom-annotation-dropdown-trigger-remaining-count-wireframe>
          
          <velt-comment-dialog-custom-annotation-dropdown-trigger-placeholder-wireframe>
              Select a category
          </velt-comment-dialog-custom-annotation-dropdown-trigger-placeholder-wireframe>
          
          <velt-comment-dialog-custom-annotation-dropdown-trigger-arrow-wireframe></velt-comment-dialog-custom-annotation-dropdown-trigger-arrow-wireframe>
      </velt-comment-dialog-custom-annotation-dropdown-trigger-wireframe>
      <velt-comment-dialog-custom-annotation-dropdown-content-wireframe>
          <velt-comment-dialog-custom-annotation-dropdown-content-item-wireframe>
              <velt-comment-dialog-custom-annotation-dropdown-content-item-label-wireframe></velt-comment-dialog-custom-annotation-dropdown-content-item-label-wireframe>
              <velt-comment-dialog-custom-annotation-dropdown-content-item-icon-wireframe></velt-comment-dialog-custom-annotation-dropdown-content-item-icon-wireframe>
          </velt-comment-dialog-custom-annotation-dropdown-content-item-wireframe>
      </velt-comment-dialog-custom-annotation-dropdown-content-wireframe>
  </velt-comment-dialog-custom-annotation-dropdown-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that indicates if a Comment has become a Ghost Comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-2.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.GhostBanner />
  </VeltWireframe>
  ```

  ```HTML HTML 
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-private-banner-wireframe></velt-comment-dialog-private-banner-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the Header.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-4.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Header>
          {/* Following subcomponents can be used outside header as well */}
          {/* Pin Dialog Header */}
          <VeltCommentDialogWireframe.Status />
          <VeltCommentDialogWireframe.Priority />
          <VeltCommentDialogWireframe.Options />
          <VeltCommentDialogWireframe.ResolveButton />
          <VeltCommentDialogWireframe.UnresolveButton />
          <VeltCommentDialogWireframe.CopyLink />

          {/* Sidebar Dialog Header */}
          <VeltCommentDialogWireframe.CommentCategory />
          <VeltCommentDialogWireframe.CommentIndex />
          <VeltCommentDialogWireframe.CommentSuggestionStatus />
          {/* Navigation Button - Only shown on sidebar when focused thread mode is on */}
          <VeltCommentDialogWireframe.NavigationButton />
          {/* Delete Button. Not added to the default components. You can explicitly add it. */}
          <VeltCommentDialogWireframe.DeleteButton></VeltCommentDialogWireframe.DeleteButton>

      </VeltCommentDialogWireframe.Header>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-header-wireframe>
          <!-- Following subcomponents can be used outside header as well -->
          <!-- Pin Dialog Header -->
          <velt-comment-dialog-status-wireframe></velt-comment-dialog-status-wireframe>
          <velt-comment-dialog-priority-wireframe></velt-comment-dialog-priority-wireframe>
          <velt-comment-dialog-options-wireframe></velt-comment-dialog-options-wireframe>
          <velt-comment-dialog-copy-link-wireframe></velt-comment-dialog-copy-link-wireframe>
          <velt-comment-dialog-resolve-button-wireframe></velt-comment-dialog-resolve-button-wireframe>
          <velt-comment-dialog-unresolve-button-wireframe></velt-comment-dialog-unresolve-button-wireframe>
          <!-- Sidebar Dialog Header -->
          <velt-comment-dialog-comment-index-wireframe></velt-comment-dialog-comment-index-wireframe>
          <velt-comment-dialog-comment-category-wireframe></velt-comment-dialog-comment-category-wireframe>
          <velt-comment-dialog-comment-suggestion-status-wireframe></velt-comment-dialog-comment-suggestion-status-wireframe>
          <!-- Navigation Button - Only shown on sidebar when focused thread mode is on -->
          <velt-comment-dialog-navigation-button-wireframe></velt-comment-dialog-navigation-button-wireframe>
          <!-- Delete Button. Not added to the default components. You can explicitly add it. -->
          <velt-comment-dialog-delete-button-wireframe></velt-comment-dialog-delete-button-wireframe>
      </velt-comment-dialog-header-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

Navigation button that appears on sidebar. Clicking on it will navigate to the comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.NavigationButton />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-navigation-button-wireframe></velt-comment-dialog-navigation-button-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the Options Dropdown

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/options-dropdown-customization.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Options>
          <VeltCommentDialogWireframe.Options.Trigger />
          <VeltCommentDialogWireframe.Options.Content>
              <VeltCommentDialogWireframe.Options.Content.MakePrivate>
                  <VeltCommentDialogWireframe.Options.Content.MakePrivate.Enable />
                  <VeltCommentDialogWireframe.Options.Content.MakePrivate.Disable />
              </VeltCommentDialogWireframe.Options.Content.MakePrivate>
              <VeltCommentDialogWireframe.Options.Content.Assign />
              <VeltCommentDialogWireframe.Options.Content.Edit />
              <VeltCommentDialogWireframe.Options.Content.Delete>
                  <VeltCommentDialogWireframe.Options.Content.Delete.Thread />
                  <VeltCommentDialogWireframe.Options.Content.Delete.Comment />
              </VeltCommentDialogWireframe.Options.Content.Delete>
              <VeltCommentDialogWireframe.Options.Content.Notification>
                  <VeltCommentDialogWireframe.Options.Content.Notification.Subscribe />
                  <VeltCommentDialogWireframe.Options.Content.Notification.Unsubscribe />
              </VeltCommentDialogWireframe.Options.Content.Notification>
          </VeltCommentDialogWireframe.Options.Content>
      </VeltCommentDialogWireframe.Options>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-options-dropdown-trigger-wireframe></velt-comment-dialog-options-dropdown-trigger-wireframe>
      <velt-comment-dialog-options-dropdown-content-wireframe>
          <velt-comment-dialog-options-dropdown-content-make-private-wireframe>
              <velt-comment-dialog-options-dropdown-content-make-private-enable-wireframe></velt-comment-dialog-options-dropdown-content-make-private-enable-wireframe>
              <velt-comment-dialog-options-dropdown-content-make-private-disable-wireframe></velt-comment-dialog-options-dropdown-content-make-private-disable-wireframe>
          </velt-comment-dialog-options-dropdown-content-make-private-wireframe>
          <velt-comment-dialog-options-dropdown-content-assign-wireframe></velt-comment-dialog-options-dropdown-content-assign-wireframe>
          <velt-comment-dialog-options-dropdown-content-edit-wireframe></velt-comment-dialog-options-dropdown-content-edit-wireframe>
          <velt-comment-dialog-options-dropdown-content-delete-wireframe>
              <velt-comment-dialog-options-dropdown-content-delete-thread-wireframe></velt-comment-dialog-options-dropdown-content-delete-thread-wireframe>
              <velt-comment-dialog-options-dropdown-content-delete-comment-wireframe></velt-comment-dialog-options-dropdown-content-delete-comment-wireframe>
          </velt-comment-dialog-options-dropdown-content-delete-wireframe>
          <velt-comment-dialog-options-dropdown-content-notification-wireframe>
              <velt-comment-dialog-options-dropdown-content-notification-subscribe-wireframe></velt-comment-dialog-options-dropdown-content-notification-subscribe-wireframe>
              <velt-comment-dialog-options-dropdown-content-notification-unsubscribe-wireframe></velt-comment-dialog-options-dropdown-content-notification-unsubscribe-wireframe>
          </velt-comment-dialog-options-dropdown-content-notification-wireframe>
      </velt-comment-dialog-options-dropdown-content-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the Priority Dropdown

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/priority-dropdown-customization.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentDialogWireframe.Priority.Trigger.Name`
    *   `VeltCommentDialogWireframe.Priority.Content.Item.Name`
  </Tab>

  <Tab title="Other Frameworks">
    *   `<velt-comment-dialog-priority-dropdown-trigger-name-wireframe>`
    *   `<velt-comment-dialog-priority-dropdown-content-item-name-wireframe>`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Priority>
          <VeltCommentDialogWireframe.Priority.Trigger>
              <VeltCommentDialogWireframe.Priority.Trigger.Icon />
              <VeltCommentDialogWireframe.Priority.Trigger.Name />
              <VeltCommentDialogWireframe.Priority.Trigger.Arrow />
          </VeltCommentDialogWireframe.Priority.Trigger>
          <VeltCommentDialogWireframe.Priority.Content>
              <VeltCommentDialogWireframe.Priority.Content.Item>
                  <VeltCommentDialogWireframe.Priority.Content.Item.Icon />
                  <VeltCommentDialogWireframe.Priority.Content.Item.Name />
                  <VeltCommentDialogWireframe.Priority.Content.Item.Tick />
              </VeltCommentDialogWireframe.Priority.Content.Item>
          </VeltCommentDialogWireframe.Priority.Content>
      </VeltCommentDialogWireframe.Priority>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-priority-dropdown-trigger-wireframe>
          <velt-comment-dialog-priority-dropdown-trigger-icon-wireframe></velt-comment-dialog-priority-dropdown-trigger-icon-wireframe>
          <velt-comment-dialog-priority-dropdown-trigger-name-wireframe></velt-comment-dialog-priority-dropdown-trigger-name-wireframe>
          <velt-comment-dialog-priority-dropdown-trigger-arrow-wireframe></velt-comment-dialog-priority-dropdown-trigger-arrow-wireframe>
      </velt-comment-dialog-priority-dropdown-trigger-wireframe>
      <velt-comment-dialog-priority-dropdown-content-wireframe>
          <velt-comment-dialog-priority-dropdown-content-item-wireframe>
              <velt-comment-dialog-priority-dropdown-content-item-icon-wireframe></velt-comment-dialog-priority-dropdown-content-item-icon-wireframe>
              <velt-comment-dialog-priority-dropdown-content-item-name-wireframe></velt-comment-dialog-priority-dropdown-content-item-name-wireframe>
              <velt-comment-dialog-priority-dropdown-content-item-tick-wireframe></velt-comment-dialog-priority-dropdown-content-item-tick-wireframe>
          </velt-comment-dialog-priority-dropdown-content-item-wireframe>
      </velt-comment-dialog-priority-dropdown-content-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that is shown near the Header when the Comment is a Private Comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-1.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.PrivateBanner />
  </VeltWireframe>
  ```

  ```HTML HTML 
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-ghost-banner-wireframe></velt-comment-dialog-ghost-banner-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the the Reaction Pin that appears after a User selects a Reaction.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/reaction-pin-customization.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltReactionPinWireframe>
          <VeltReactionPinWireframe.Emoji />
          <VeltReactionPinWireframe.Count />
      </VeltReactionPinWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-reaction-pin-wireframe>
          <velt-reaction-pin-emoji-wireframe><velt-reaction-pin-emoji-wireframe>
          <velt-reaction-pin-count-wireframe><velt-reaction-pin-count-wireframe>
      </velt-reaction-pin-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the tooltip that appears when a User hovers over a Reaction

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/reaction-tooltip-customization.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltReactionPinTooltipWireframe>
          <VeltReactionPinTooltipWireframe.Users>
              <VeltReactionPinTooltipWireframe.Users.User>
                  <VeltReactionPinTooltipWireframe.Users.User.Avatar />
                  <VeltReactionPinTooltipWireframe.Users.User.Name />
              </VeltReactionPinTooltipWireframe.Users.User>
          </VeltReactionPinTooltipWireframe.Users>
      </VeltReactionPinTooltipWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML 
  <velt-wireframe style="display:none;">
      <velt-reaction-pin-tooltip-wireframe>
          <velt-reaction-pin-tooltip-users-wireframe>
              <velt-reaction-pin-tooltip-user-wireframe>
                  <velt-reaction-pin-tooltip-user-avatar-wireframe></velt-reaction-pin-tooltip-user-avatar-wireframe>
                  <velt-reaction-pin-tooltip-user-name-wireframe></velt-reaction-pin-tooltip-user-name-wireframe>
              </velt-reaction-pin-tooltip-user-wireframe>
          </velt-reaction-pin-tooltip-users-wireframe>
      </velt-reaction-pin-tooltip-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the button used to add a Reaction

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/reaction-tool-customization.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltReactionToolWireframe>
      # Your custom element
      </VeltReactionToolWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
       <velt-reaction-tool-wireframe>
      # Your custom element
      </velt-reaction-tool-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the panel of all Reactions that have been added to a Comment

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/reaction-panel-customization.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltReactionsPanelWireframe>
          <VeltReactionsPanelWireframe.Items>
              <VeltReactionsPanelWireframe.Items.Item>
                  <VeltReactionsPanelWireframe.Items.Item.Emoji />
              </VeltReactionsPanelWireframe.Items.Item>
          </VeltReactionsPanelWireframe.Items>
       </VeltReactionsPanelWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-reactions-panel-wireframe>
          <velt-reactions-panel-items-wireframe>
              <velt-reactions-panel-item-wireframe>
                  <velt-reactions-panel-item-emoji-wireframe></velt-reactions-panel-item-emoji-wireframe>
              </velt-reactions-panel-item-wireframe>
          </velt-reactions-panel-items-wireframe>
      </velt-reactions-panel-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the Sign In button that appears when a User is a Guest User

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-10.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.SignIn />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-sign-in-wireframe></velt-comment-dialog-sign-in-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the Status Dropdown

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/status-dropdown-customization.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentDialogWireframe.Status.Trigger.Name`
    *   `VeltCommentDialogWireframe.Status.Content.Item.Name`
  </Tab>

  <Tab title="Other Frameworks">
    *   `<velt-comment-dialog-status-dropdown-trigger-name-wireframe>`
    *   `<velt-comment-dialog-status-dropdown-content-item-name-wireframe>`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Status>
          <VeltCommentDialogWireframe.Status.Trigger>
              <VeltCommentDialogWireframe.Status.Trigger.Icon />
              <VeltCommentDialogWireframe.Status.Trigger.Name />
              <VeltCommentDialogWireframe.Status.Trigger.Arrow />
          </VeltCommentDialogWireframe.Status.Trigger>
          <VeltCommentDialogWireframe.Status.Content>
              <VeltCommentDialogWireframe.Status.Content.Item>
                  <VeltCommentDialogWireframe.Status.Content.Item.Icon />
                  <VeltCommentDialogWireframe.Status.Content.Item.Name />
              </VeltCommentDialogWireframe.Status.Content.Item>
          </VeltCommentDialogWireframe.Status.Content>
      </VeltCommentDialogWireframe.Status>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-status-dropdown-trigger-wireframe>
          <velt-comment-dialog-status-dropdown-trigger-icon-wireframe></velt-comment-dialog-status-dropdown-trigger-icon-wireframe>
          <velt-comment-dialog-status-dropdown-trigger-name-wireframe></velt-comment-dialog-status-dropdown-trigger-name-wireframe>
          <velt-comment-dialog-status-dropdown-trigger-arrow-wireframe></velt-comment-dialog-status-dropdown-trigger-arrow-wireframe>
      </velt-comment-dialog-status-dropdown-trigger-wireframe>

      <velt-comment-dialog-status-dropdown-content-wireframe>
          <velt-comment-dialog-status-dropdown-content-item-wireframe>
              <velt-comment-dialog-status-dropdown-content-item-icon-wireframe></velt-comment-dialog-status-dropdown-content-item-icon-wireframe>
              <velt-comment-dialog-status-dropdown-content-item-name-wireframe></velt-comment-dialog-status-dropdown-content-item-name-wireframe>
          </velt-comment-dialog-status-dropdown-content-item-wireframe>
      </velt-comment-dialog-status-dropdown-content-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the Accept or Reject button is Moderator Mode.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-12.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.SuggestionAction>
          <VeltCommentDialogWireframe.SuggestionAction.Accept />
          <VeltCommentDialogWireframe.SuggestionAction.Reject />
      </VeltCommentDialogWireframe.SuggestionAction>
  </VeltWireframe>
  ```

  ```HTML HTML 
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-suggestion-action-wireframe>
          <velt-comment-dialog-suggestion-action-accept-wireframe></velt-comment-dialog-suggestion-action-accept-wireframe>
          <velt-comment-dialog-suggestion-action-reject-wireframe></velt-comment-dialog-suggestion-action-reject-wireframe>
      </velt-comment-dialog-suggestion-action-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comment Dialog that represents the Upgrade button.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-11.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentDialogWireframe.Upgrade />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-dialog-upgrade-wireframe></velt-comment-dialog-upgrade-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The Pin that appears on the DOM when you place a Comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default comment pin component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-pin-light.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-pin-all-states-light.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentPinWireframe>
          {/* Ghost Comment Indicator */}
          <VeltCommentPinWireframe.GhostCommentIndicator/>
          {/* Index */}
          <VeltCommentPinWireframe.Index/>
          {/* Private Comment Indicator */}
          <VeltCommentPinWireframe.PrivateCommentIndicator/>
          {/* Triangle */}
          <VeltCommentPinWireframe.Triangle/>
          {/* Unread Comment Indicator */}
          <VeltCommentPinWireframe.UnreadCommentIndicator/>
      </VeltCommentPinWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-pin-wireframe>
          <!-- Ghost Comment Indicator -->
          <velt-comment-pin-ghost-comment-indicator-wireframe></velt-comment-pin-ghost-comment-indicator-wireframe>
          <!-- Index -->
          <velt-comment-pin-index-wireframe></velt-comment-pin-index-wireframe>
          <!-- Private Comment Indicator -->
          <velt-comment-pin-private-comment-indicator-wireframe></velt-comment-pin-private-comment-indicator-wireframe>
          <!-- Triangle -->
          <velt-comment-pin-triangle-wireframe></velt-comment-pin-triangle-wireframe>
          <!-- Unread Comment Indicator -->
          <velt-comment-pin-unread-comment-indicator-wireframe></velt-comment-pin-unread-comment-indicator-wireframe>
      </velt-comment-pin-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltComments pinShadowDOM={false} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enablePinShadowDOM();
    commentElement.disablePinShadowDOM();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```jsx
    <velt-comments pin-shadow-dom="false"></velt-comments>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enablePinShadowDOM();
    commentElement.disablePinShadowDOM();
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-pin-1.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-pin-2.png)
By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

`Default: false`

Below are the examples to enable Dark Mode for comments pin:

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```js
    <VeltComments pinDarkMode={true}/>
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```js
    <velt-comments pin-dark-mode="true"></velt-comments>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# null

The subcomponent on the Comment Pin that indicates whether the Comment is a Ghost Comment

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/Ghost_comments.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentPinWireframe.GhostCommentIndicator />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-pin-ghost-comment-indicator-wireframe></velt-comment-pin-ghost-comment-indicator-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Comment Pin that indicates the index number of the Comment

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/Index_counter.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentPinWireframe.Index/>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-pin-index-wireframe></velt-comment-pin-index-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Comment Pin that indicates whether the Comment is a Private Comment

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/Private_comments.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentPinWireframe.PrivateCommentIndicator/>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-pin-private-comment-indicator-wireframe></velt-comment-pin-private-comment-indicator-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Comment Pin that appears as a triangle in the top right corner of a Popover Comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/Cell_indicator.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentPinWireframe.Triangle/>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-pin-triangle-wireframe></velt-comment-pin-triangle-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Comment Pin that indicates whether a Comment hasn't been read yet by the User.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/Unread_indicator.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentPinWireframe.UnreadCommentIndicator/>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-pin-unread-comment-indicator-wireframe></velt-comment-pin-unread-comment-indicator-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

### Example

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentPlayerTimeline shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comment-player-timeline shadow-dom="false"></velt-comment-player-timeline>
    ```
  </Tab>
</Tabs>


# Overview

The button to add new comments.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default comment tool component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-tool-light.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentToolWireframe>
      # Your custom element
      </VeltCommentToolWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-tool-wireframe>
      # Your custom element
      </velt-comment-tool-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentTool shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-comment-tool shadow-dom="false"></velt-comment-tool>
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-tool-1.png)

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltCommentTool darkMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-comment-tool dark-mode="true"></velt-comment-tool>
    ```
  </Tab>
</Tabs>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

### Example

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltVideoPlayer shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-video-player shadow-dom="false"></velt-video-player>
    ```
  </Tab>
</Tabs>


# Overview



<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default comments sidebar component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/sidebar-light.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/sidebar-breakdown-light.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe>
          {/* Skeleton */}
          <VeltCommentsSidebarWireframe.Skeleton />
          <VeltCommentsSidebarWireframe.Panel>
              {/* Header - Contains search, status filters, close button etc */}
              <VeltCommentsSidebarWireframe.Header />
              {/* Custom Action Button - Use to define custom filter, sorting, grouping */}
              <VeltCommentsSidebarWireframe.ActionButton id="all" type="toggle" />
              {/* Filter - The filter panel that contains the default system filters */}
              <VeltCommentsSidebarWireframe.Filter />
              {/* List - The list of comments that appear in the sidebar */}
              <VeltCommentsSidebarWireframe.List />
              {/* Empty Placeholder - The placeholder that appears when there are no comments */}
              <VeltCommentsSidebarWireframe.EmptyPlaceholder />
              {/* Reset Filter Button - Not included in default component */}
              <VeltCommentsSidebarWireframe.ResetFilterButton />
              {/* Page Mode Composer - The composer that appears when the page mode is enabled */}
              <VeltCommentsSidebarWireframe.PageModeComposer />
          </VeltCommentsSidebarWireframe.Panel>
          {/* Focused Thread - This only appears when focused thread mode is enabled */}
          <VeltCommentsSidebarWireframe.FocusedThread />
      </VeltCommentsSidebarWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-wireframe>
          <!-- Skeleton -->
          <velt-comments-sidebar-skeleton-wireframe></velt-comments-sidebar-skeleton-wireframe>
          <velt-comments-sidebar-panel-wireframe>
              <!-- Header -->
              <velt-comments-sidebar-header-wireframe></velt-comments-sidebar-header-wireframe>
              <!-- Custom Action Button - Use to define custom filter, sorting, grouping -->
              <velt-comments-sidebar-action-button-wireframe id="all" type="toggle"></velt-comments-sidebar-action-button-wireframe>
              <!-- Comments Sidebar -->
              <velt-comments-sidebar-filter-wireframe></velt-comments-sidebar-filter-wireframe>
              <!-- List -->
              <velt-comments-sidebar-list-wireframe></velt-comments-sidebar-list-wireframe>
              <!-- Empty Placeholder -->
              <velt-comments-sidebar-empty-placeholder-wireframe></velt-comments-sidebar-empty-placeholder-wireframe>
              <!-- Reset Filter Button - Not included in default component -->
              <velt-comments-sidebar-reset-filter-button-wireframe></velt-comments-sidebar-reset-filter-button-wireframe>
              <!-- Page Mode Composer-->
              <velt-comments-sidebar-page-mode-composer-wireframe></velt-comments-sidebar-page-mode-composer-wireframe>
          </velt-comments-sidebar-panel-wireframe>
      </velt-comments-sidebar-wireframe>
      
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltCommentsSidebar shadowDom={false} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableSidebarShadowDOM();
    commentElement.disableSidebarShadowDOM();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```jsx
    <velt-comments-sidebar shadow-dom="false"></velt-comments-sidebar>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableSidebarShadowDOM();
    commentElement.disableSidebarShadowDOM();
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-sidebar-1.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/sidebar-breakdown-dark.png)
By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

`Default: false`

To enable Dark Mode for comments sidebar:

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```js
    <VeltCommentsSidebar darkMode={true} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```js
    <velt-comments-sidebar dark-mode="true"></velt-comments-sidebar>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# null



<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.ActionButton id="all" type="toggle" />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-action-button-wireframe id="all" type="toggle"></velt-comments-sidebar-action-button-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar that represents the placeholder when there are no Comments

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/sidebar-placeholder.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.EmptyPlaceholder/>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-empty-placeholder-wireframe></velt-comments-sidebar-empty-placeholder-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar that represents the filter that is used to filter what Comments appear in the Sidebar

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/sidebar-filter.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter>
          {/* Title */}
          <VeltCommentsSidebarWireframe.Filter.Title />
          {/* Close Button */}
          <VeltCommentsSidebarWireframe.Filter.CloseButton />
          {/* Location */}
          <VeltCommentsSidebarWireframe.Filter.Location />
          {/* People */}
          <VeltCommentsSidebarWireframe.Filter.People />
          {/* Category */}
          <VeltCommentsSidebarWireframe.Filter.Category />
          {/* Priority */}
          <VeltCommentsSidebarWireframe.Filter.Priority />
          {/* CommentType */}
          <VeltCommentsSidebarWireframe.Filter.CommentType />
          {/* Versions */}
          <VeltCommentsSidebarWireframe.Filter.Versions />
          {/* GroupBy */}
          <VeltCommentsSidebarWireframe.Filter.GroupBy />
          {/* Done Button */}
          <VeltCommentsSidebarWireframe.Filter.DoneButton />
      </VeltCommentsSidebarWireframe.Filter>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-wireframe>
          <!--  Title -->
          <velt-comments-sidebar-filter-title-wireframe></velt-comments-sidebar-filter-title-wireframe>
          <!--  Close Button -->
          <velt-comments-sidebar-filter-close-button-wireframe></velt-comments-sidebar-filter-close-button-wireframe>
          <!--  Location -->
          <velt-comments-sidebar-filter-location-wireframe></velt-comments-sidebar-filter-location-wireframe>
          <!-- People -->
          <velt-comments-sidebar-filter-people-wireframe>/velt-comments-sidebar-filter-people-wireframe>
          <!-- Category -->
          <velt-comments-sidebar-filter-category-wireframe></velt-comments-sidebar-filter-category-wireframe>
          <!-- Comment Type -->
          <velt-comments-sidebar-filter-comment-type-wireframe></velt-comments-sidebar-filter-comment-type-wireframe>
          <!-- Priority -->
          <velt-comments-sidebar-filter-priority-wireframe></velt-comments-sidebar-filter-priority-wireframe>
          <!-- Versions -->
          <velt-comments-sidebar-filter-versions-wireframe></velt-comments-sidebar-filter-versions-wireframe>
          <!-- Group By -->
          <velt-comments-sidebar-filter-group-by-wireframe></velt-comments-sidebar-filter-group-by-wireframe>
          <!-- Done Button -->
          <velt-comments-sidebar-filter-done-button-wireframe></velt-comments-sidebar-filter-done-button-wireframe>
      </velt-comments-sidebar-filter-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Category

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-category.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.Category>
         <VeltCommentsSidebarWireframe.Filter.Category.Name />
         <VeltCommentsSidebarWireframe.Filter.Category.Item>
           <VeltCommentsSidebarWireframe.Filter.Category.Item.Checkbox>
             <VeltCommentsSidebarWireframe.Filter.Category.Item.Checkbox.Checked />
             <VeltCommentsSidebarWireframe.Filter.Category.Item.Checkbox.Unchecked />
           </VeltCommentsSidebarWireframe.Filter.Category.Item.Checkbox>
           <VeltCommentsSidebarWireframe.Filter.Category.Item.Name />
           <VeltCommentsSidebarWireframe.Filter.Category.Item.Count />
         </VeltCommentsSidebarWireframe.Filter.Category.Item>
      </VeltCommentsSidebarWireframe.Filter.Category>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-category-wireframe>
          <velt-comments-sidebar-filter-name-wireframe></velt-comments-sidebar-filter-name-wireframe>
          <velt-comments-sidebar-filter-item-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-wireframe></velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
              <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
          </velt-comments-sidebar-filter-item-wireframe>
      </velt-comments-sidebar-filter-category-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Close button

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-close.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.CloseButton />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-close-button-wireframe></velt-comments-sidebar-filter-close-button-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Comment Type filter

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/comment-type-filter.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.CommentType>
          <VeltCommentsSidebarWireframe.Filter.CommentType.Name />
          <VeltCommentsSidebarWireframe.Filter.CommentType.Item>
              <VeltCommentsSidebarWireframe.Filter.CommentType.Item.Checkbox>
                  <VeltCommentsSidebarWireframe.Filter.CommentType.Item.Checkbox.Checked />
                  <VeltCommentsSidebarWireframe.Filter.CommentType.Item.Checkbox.Unchecked />
              </VeltCommentsSidebarWireframe.Filter.CommentType.Item.Checkbox>
              <VeltCommentsSidebarWireframe.Filter.CommentType.Item.Name />
              <VeltCommentsSidebarWireframe.Filter.CommentType.Item.Count />
          </VeltCommentsSidebarWireframe.Filter.CommentType.Item>
      </VeltCommentsSidebarWireframe.Filter.CommentType>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-comment-type-wireframe>
          <velt-comments-sidebar-filter-name-wireframe></velt-comments-sidebar-filter-name-wireframe>
          <velt-comments-sidebar-filter-item-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-wireframe></velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
              <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
          </velt-comments-sidebar-filter-item-wireframe>
      </velt-comments-sidebar-filter-comment-type-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Done Button

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-done.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.DoneButton />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-done-button-wireframe></velt-comments-sidebar-filter-done-button-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

Used to customize all the filter option items of the Comments Sidebar Filter at once

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-item.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentsSidebarWireframe.Search`
    *   `VeltCommentsSidebarWireframe.Filter.Item.Count`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-comments-sidebar-search-wireframe`
    *   `velt-comments-sidebar-filter-item-count-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.Item>
          <VeltCommentsSidebarWireframe.Filter.Item.Checkbox>
              <VeltCommentsSidebarWireframe.Filter.Item.Checkbox.Checked />
              <VeltCommentsSidebarWireframe.Filter.Item.Checkbox.Unchecked />
          </VeltCommentsSidebarWireframe.Filter.Item.Checkbox>
          <VeltCommentsSidebarWireframe.Filter.Item.Name />
          <VeltCommentsSidebarWireframe.Filter.Item.Count />
     </VeltCommentsSidebarWireframe.Filter.Item>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-item-wireframe>
          <velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-checked-wireframe></velt-comments-sidebar-filter-item-checkbox-checked-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-unchecked-wireframe></velt-comments-sidebar-filter-item-checkbox-unchecked-wireframe>
          </velt-comments-sidebar-filter-item-checkbox-wireframe>
          <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
          <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
      </velt-comments-sidebar-filter-item-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Groupby filter option

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-groupby.png)

<RequestExample>
  ```jsx eact / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.GroupBy>
          <VeltCommentsSidebarWireframe.Filter.GroupBy.Name />
          <VeltCommentsSidebarWireframe.Filter.GroupBy.Item>
              <VeltCommentsSidebarWireframe.Filter.GroupBy.Item.Checkbox>
                  <VeltCommentsSidebarWireframe.Filter.GroupBy.Item.Checkbox.Checked />
                  <VeltCommentsSidebarWireframe.Filter.GroupBy.Item.Checkbox.Unchecked />
              </VeltCommentsSidebarWireframe.Filter.GroupBy.Item.Checkbox>
              <VeltCommentsSidebarWireframe.Filter.GroupBy.Item.Name />
              <VeltCommentsSidebarWireframe.Filter.GroupBy.Item.Count />
          </VeltCommentsSidebarWireframe.Filter.GroupBy.Item>
      </VeltCommentsSidebarWireframe.Filter.GroupBy>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-group-by-wireframe>
          <velt-comments-sidebar-filter-name-wireframe></velt-comments-sidebar-filter-name-wireframe>
          <velt-comments-sidebar-filter-item-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-wireframe></velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
              <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
          </velt-comments-sidebar-filter-item-wireframe>
      </velt-comments-sidebar-filter-group-by-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Location filter

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-location.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.Location>
          <VeltCommentsSidebarWireframe.Filter.Location.Name />
          <VeltCommentsSidebarWireframe.Filter.Location.Item>
              <VeltCommentsSidebarWireframe.Filter.Location.Item.Checkbox>
                  <VeltCommentsSidebarWireframe.Filter.Location.Item.Checkbox.Checked />
                  <VeltCommentsSidebarWireframe.Filter.Location.Item.Checkbox.Unchecked />
              </VeltCommentsSidebarWireframe.Filter.Location.Item.Checkbox>
              <VeltCommentsSidebarWireframe.Filter.Location.Item.Name />
              <VeltCommentsSidebarWireframe.Filter.Location.Item.Count />
          </VeltCommentsSidebarWireframe.Filter.Location.Item>
          <VeltCommentsSidebarWireframe.Filter.Location.ViewAll />
      </VeltCommentsSidebarWireframe.Filter.Location>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-location-wireframe>
          <velt-comments-sidebar-filter-name-wireframe></velt-comments-sidebar-filter-name-wireframe>
          <velt-comments-sidebar-filter-item-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-wireframe></velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
              <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
          </velt-comments-sidebar-filter-item-wireframe>
          <velt-comments-sidebar-filter-view-all-wireframe></velt-comments-sidebar-filter-view-all-wireframe>
      </velt-comments-sidebar-filter-location-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the People filter

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-people.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.People>
          <VeltCommentsSidebarWireframe.Filter.People.Name />
          <VeltCommentsSidebarWireframe.Filter.People.Item>
              <VeltCommentsSidebarWireframe.Filter.People.Item.Checkbox>
                  <VeltCommentsSidebarWireframe.Filter.People.Item.Checkbox.Checked />
                  <VeltCommentsSidebarWireframe.Filter.People.Item.Checkbox.Unchecked />
              </VeltCommentsSidebarWireframe.Filter.People.Item.Checkbox>
              <VeltCommentsSidebarWireframe.Filter.People.Item.Name />
              <VeltCommentsSidebarWireframe.Filter.People.Item.Count />
          </VeltCommentsSidebarWireframe.Filter.People.Item>
      </VeltCommentsSidebarWireframe.Filter.People>
  </VeltWireframe>
  ```

  ```HTML HTML  
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-people-wireframe>
          <velt-comments-sidebar-filter-name-wireframe></velt-comments-sidebar-filter-name-wireframe>
          <velt-comments-sidebar-filter-item-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-wireframe></velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
              <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
          </velt-comments-sidebar-filter-item-wireframe>
      </velt-comments-sidebar-filter-people-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Priority filter

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-priority.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.Priority>
          <VeltCommentsSidebarWireframe.Filter.Priority.Name />
          <VeltCommentsSidebarWireframe.Filter.Priority.Item>
              <VeltCommentsSidebarWireframe.Filter.Priority.Item.Checkbox>
                  <VeltCommentsSidebarWireframe.Filter.Priority.Item.Checkbox.Checked />
                  <VeltCommentsSidebarWireframe.Filter.Priority.Item.Checkbox.Unchecked />
              </VeltCommentsSidebarWireframe.Filter.Priority.Item.Checkbox>
          <VeltCommentsSidebarWireframe.Filter.Priority.Item.Name />
          <VeltCommentsSidebarWireframe.Filter.Priority.Item.Count />
      </VeltCommentsSidebarWireframe.Filter.Priority.Item>
      </VeltCommentsSidebarWireframe.Filter.Priority>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-priority-wireframe>
          <velt-comments-sidebar-filter-name-wireframe></velt-comments-sidebar-filter-name-wireframe>
          <velt-comments-sidebar-filter-item-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-wireframe></velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
              <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
          </velt-comments-sidebar-filter-item-wireframe>
      </velt-comments-sidebar-filter-priority-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Title

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-title.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.Title />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-title-wireframe></velt-comments-sidebar-filter-title-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar Filter that represents the Version filter

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-versions.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Filter.Versions>
          <VeltCommentsSidebarWireframe.Filter.Versions.Name />
          <VeltCommentsSidebarWireframe.Filter.Versions.Item>
              <VeltCommentsSidebarWireframe.Filter.Versions.Item.Checkbox>
                  <VeltCommentsSidebarWireframe.Filter.Versions.Item.Checkbox.Checked />
                  <VeltCommentsSidebarWireframe.Filter.Versions.Item.Checkbox.Unchecked />
              </VeltCommentsSidebarWireframe.Filter.Versions.Item.Checkbox>
              <VeltCommentsSidebarWireframe.Filter.Versions.Item.Name />
              <VeltCommentsSidebarWireframe.Filter.Versions.Item.Count />
          </VeltCommentsSidebarWireframe.Filter.Versions.Item>
      </VeltCommentsSidebarWireframe.Filter.Versions>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-filter-versions-wireframe>
          <velt-comments-sidebar-filter-name-wireframe></velt-comments-sidebar-filter-name-wireframe>
          <velt-comments-sidebar-filter-item-wireframe>
              <velt-comments-sidebar-filter-item-checkbox-wireframe></velt-comments-sidebar-filter-item-checkbox-wireframe>
              <velt-comments-sidebar-filter-item-name-wireframe></velt-comments-sidebar-filter-item-name-wireframe>
              <velt-comments-sidebar-filter-item-count-wireframe></velt-comments-sidebar-filter-item-count-wireframe>
          </velt-comments-sidebar-filter-item-wireframe>
      </velt-comments-sidebar-filter-versions-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null



<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.FocusedThread>
          {/* Back Button to back to default view with all threads */}
          <VeltCommentsSidebarWireframe.FocusedThread.BackButton />
          {/* Container that contains the comment dialog */}
          <VeltCommentsSidebarWireframe.FocusedThread.DialogContainer />
      </VeltCommentsSidebarWireframe.FocusedThread>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-focused-thread-wireframe>
          <!-- Back Button to back to default view with all threads -->
          <velt-comments-sidebar-focused-thread-back-button-wireframe></velt-comments-sidebar-focused-thread-back-button-wireframe>
          <!-- Container that contains the comment dialog -->
          <velt-comments-sidebar-focused-thread-dialog-container-wireframe></velt-comments-sidebar-focused-thread-dialog-container-wireframe>
      </velt-comments-sidebar-focused-thread-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar that represents the Header of the Sidebar

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/sidebar-header.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltCommentsSidebarWireframe.Search`
    *   `VeltCommentsSidebarWireframe.Status`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-comments-sidebar-search-wireframe`
    *   `velt-comments-sidebar-status-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Header>
          <VeltCommentsSidebarWireframe.CloseButton /> {/* Not shown for embedded comments sidebar */}
          <VeltCommentsSidebarWireframe.Search/>
          <VeltCommentsSidebarWireframe.Status/>

          {/* Not included in the default component */}
          <VeltCommentsSidebarWireframe.LocationFilterDropdown/>

          {/* Not included in the default component */}
          <VeltCommentsSidebarWireframe.MinimalFilterDropdown/>

          {/* Not included in the default component */}
          <VeltCommentsSidebarWireframe.MinimalActionsDropdown/>

          <VeltCommentsSidebarWireframe.FilterButton/>
      </VeltCommentsSidebarWireframe.Header>
  </VeltWireframe>
  ```

  ```HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-header-wireframe>
          <velt-comments-sidebar-close-button-wireframe></velt-comments-sidebar-close-button-wireframe> <!-- Not shown for embedded comments sidebar -->
          <velt-comments-sidebar-search-wireframe></velt-comments-sidebar-search-wireframe>
          <velt-comments-sidebar-status-wireframe></velt-comments-sidebar-status-wireframe>

          <!-- Not included in the default component -->
          <velt-comments-sidebar-location-filter-dropdown-wireframe></velt-comments-sidebar-location-filter-dropdown-wireframe>

          <!-- Not included in the default component -->
          <velt-comments-sidebar-minimal-filter-dropdown-wireframe></velt-comments-sidebar-minimal-filter-dropdown-wireframe>

          <!-- Not included in the default component -->
          <velt-comments-sidebar-minimal-actions-dropdown-wireframe></velt-comments-sidebar-minimal-actions-dropdown-wireframe>

          <velt-comments-sidebar-filter-button-wireframe></velt-comments-sidebar-filter-button-wireframe>
      </velt-comments-sidebar-header-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview



<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

This component is not included in the default Comments Sidebar component. You need to explicitly add it to the sidebar wireframe.

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.LocationFilterDropdown>
          <VeltCommentsSidebarWireframe.LocationFilterDropdown.Trigger>
              <VeltCommentsSidebarWireframe.LocationFilterDropdown.Trigger.Label />
          </VeltCommentsSidebarWireframe.LocationFilterDropdown.Trigger>
          <VeltCommentsSidebarWireframe.LocationFilterDropdown.Content />
      </VeltCommentsSidebarWireframe.LocationFilterDropdown>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-location-filter-dropdown-wireframe>
          <velt-comments-sidebar-location-filter-dropdown-trigger-wireframe>
              <velt-comments-sidebar-location-filter-dropdown-trigger-label-wireframe></velt-comments-sidebar-location-filter-dropdown-trigger-label-wireframe>
          </velt-comments-sidebar-location-filter-dropdown-trigger-wireframe>
          <velt-comments-sidebar-location-filter-dropdown-content-wireframe></velt-comments-sidebar-location-filter-dropdown-content-wireframe>
      </velt-comments-sidebar-location-filter-dropdown-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview



<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

*   This enables actions like `Mark all read` and `Mark all resolved` in the sidebar. By default it's not enabled. You need to explicitly add the wireframe to the sidebar.

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.MinimalActionsDropdown>
          <VeltCommentsSidebarWireframe.MinimalActionsDropdown.Trigger />
          <VeltCommentsSidebarWireframe.MinimalActionsDropdown.Content>
              <VeltCommentsSidebarWireframe.MinimalActionsDropdown.Content.MarkAllRead />
              <VeltCommentsSidebarWireframe.MinimalActionsDropdown.Content.MarkAllResolved />
          </VeltCommentsSidebarWireframe.MinimalActionsDropdown.Content>
      </VeltCommentsSidebarWireframe.MinimalActionsDropdown>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-minimal-actions-dropdown-wireframe>
          <velt-comments-sidebar-minimal-actions-dropdown-trigger-wireframe></velt-comments-sidebar-minimal-actions-dropdown-trigger-wireframe>
          <velt-comments-sidebar-minimal-actions-dropdown-content-wireframe>
              <velt-comments-sidebar-minimal-actions-dropdown-content-mark-all-read-wireframe></velt-comments-sidebar-minimal-actions-dropdown-content-mark-all-read-wireframe>
              <velt-comments-sidebar-minimal-actions-dropdown-content-mark-all-resolved-wireframe></velt-comments-sidebar-minimal-actions-dropdown-content-mark-all-resolved-wireframe>
          </velt-comments-sidebar-minimal-actions-dropdown-content-wireframe>
      </velt-comments-sidebar-minimal-actions-dropdown-wireframe>

  </velt-wireframe>
  ```
</RequestExample>


# Overview



<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

*   This enables minimal filtering and sorting dropdown in the sidebar. By default it's not enabled. You need to explicitly add the wireframe to the sidebar. It includes options like:
*   Filter by `All`
*   Filter by `Unread`
*   Filter by `Read`
*   Filter by `Resolved`
*   Sort by `Unread`
*   Sort by `Last Updated Timestamp`

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.MinimalFilterDropdown>
          <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Trigger />
          <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content>
              <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SortDate>
                  <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SelectedIcon />
                  Sort date
              </VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SortDate>
              <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SortUnread>
                  <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SelectedIcon />
                  Sort unread
              </VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SortUnread>
              <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterAll>
                  <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SelectedIcon />
                  Filter all
              </VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterAll>
              <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterUnread>
                  <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SelectedIcon />
                  Filter unread
              </VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterUnread>
              <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterRead>
                  <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SelectedIcon />
                  Filter read
              </VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterRead>
              <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterResolved>
                  <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.SelectedIcon />
                  Filter resolved
              </VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterResolved>
          </VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content>
      </VeltCommentsSidebarWireframe.MinimalFilterDropdown>

  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-minimal-filter-dropdown-wireframe>
          <velt-comments-sidebar-minimal-filter-dropdown-trigger-wireframe></velt-comments-sidebar-minimal-filter-dropdown-trigger-wireframe>
          <velt-comments-sidebar-minimal-filter-dropdown-content-wireframe>
              <velt-comments-sidebar-minimal-filter-dropdown-content-sort-date-wireframe>
                  <velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe></velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe>
                  Sort by date
              </velt-comments-sidebar-minimal-filter-dropdown-content-sort-date-wireframe>

              <velt-comments-sidebar-minimal-filter-dropdown-content-sort-unread-wireframe>
                  <velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe></velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe>
                  Sort by unread
              </velt-comments-sidebar-minimal-filter-dropdown-content-sort-unread-wireframe>

              <velt-comments-sidebar-minimal-filter-dropdown-content-filter-all-wireframe>
                  <velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe></velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe>
                  Unread or Read
              </velt-comments-sidebar-minimal-filter-dropdown-content-filter-all-wireframe>

              <velt-comments-sidebar-minimal-filter-dropdown-content-filter-unread-wireframe>
                  <velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe></velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe>
                  Unread only
              </velt-comments-sidebar-minimal-filter-dropdown-content-filter-unread-wireframe>

              <velt-comments-sidebar-minimal-filter-dropdown-content-filter-read-wireframe>
                  <velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe></velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe>
                  Read only
              </velt-comments-sidebar-minimal-filter-dropdown-content-filter-read-wireframe>

              <velt-comments-sidebar-minimal-filter-dropdown-content-filter-resolved-wireframe>
                  <velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe></velt-comments-sidebar-minimal-filter-dropdown-content-selected-icon-wireframe>
                  Resolved
              </velt-comments-sidebar-minimal-filter-dropdown-content-filter-resolved-wireframe>
          </velt-comments-sidebar-minimal-filter-dropdown-content-wireframe>
      </velt-comments-sidebar-minimal-filter-dropdown-wireframe>

  </velt-wireframe>
  ```
</RequestExample>


# Overview



<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/comments-sidebar-dropdown.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Status>
          <VeltCommentsSidebarWireframe.Status.Trigger />
          <VeltCommentsSidebarWireframe.Status.Content />
      </VeltCommentsSidebarWireframe.Status>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-status-dropdown-wireframe>
          <velt-comments-sidebar-status-dropdown-trigger-wireframe></velt-comments-sidebar-status-dropdown-trigger-wireframe>
          <velt-comments-sidebar-status-dropdown-content-wireframe></velt-comments-sidebar-status-dropdown-content-wireframe>
      </velt-comments-sidebar-status-dropdown-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Content



<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-status-content.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Status.Content>
          <VeltCommentsSidebarWireframe.Status.Content.Item>
          <VeltCommentsSidebarWireframe.Status.Content.Item.Icon />
          <VeltCommentsSidebarWireframe.Status.Content.Item.Name />
          <VeltCommentsSidebarWireframe.Status.Content.Item.Count />
          <VeltCommentsSidebarWireframe.Status.Content.Item.Checkbox>
              <VeltCommentsSidebarWireframe.Status.Content.Item.Checkbox.Checked />
              <VeltCommentsSidebarWireframe.Status.Content.Item.Checkbox.Unchecked />
          </VeltCommentsSidebarWireframe.Status.Content.Item.Checkbox>
          </VeltCommentsSidebarWireframe.Status.Content.Item>
      </VeltCommentsSidebarWireframe.Status.Content>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-status-dropdown-content-wireframe>
          <velt-comments-sidebar-status-dropdown-content-item-wireframe>
              <velt-comments-sidebar-status-dropdown-content-item-icon-wireframe></velt-comments-sidebar-status-dropdown-content-item-icon-wireframe>
              <velt-comments-sidebar-status-dropdown-content-item-name-wireframe></velt-comments-sidebar-status-dropdown-content-item-name-wireframe>
              <velt-comments-sidebar-status-dropdown-content-item-count-wireframe></velt-comments-sidebar-status-dropdown-content-item-count-wireframe>
              <velt-comments-sidebar-status-dropdown-content-item-checkbox-wireframe>
                  <velt-comments-sidebar-status-dropdown-content-item-checkbox-unchecked-wireframe></velt-comments-sidebar-status-dropdown-content-item-checkbox-unchecked-wireframe>
                  <velt-comments-sidebar-status-dropdown-content-item-checkbox-checked-wireframe></velt-comments-sidebar-status-dropdown-content-item-checkbox-checked-wireframe>
              </velt-comments-sidebar-status-dropdown-content-item-checkbox-wireframe>
          </velt-comments-sidebar-status-dropdown-content-item-wireframe>
      </velt-comments-sidebar-status-dropdown-content-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Trigger



<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/filter-status-trigger.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Status.Trigger>
          <VeltCommentsSidebarWireframe.Status.Trigger.Name />
          <VeltCommentsSidebarWireframe.Status.Trigger.Arrow />
          <VeltCommentsSidebarWireframe.Status.Trigger.Indicator />
      </VeltCommentsSidebarWireframe.Status.Trigger>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-status-dropdown-trigger-wireframe>
          <velt-comments-sidebar-status-dropdown-trigger-name-wireframe></velt-comments-sidebar-status-dropdown-trigger-name-wireframe>
          <velt-comments-sidebar-status-dropdown-trigger-arrow-wireframe></velt-comments-sidebar-status-dropdown-trigger-arrow-wireframe>
          <velt-comments-sidebar-status-dropdown-trigger-indicator-wireframe></velt-comments-sidebar-status-dropdown-trigger-indicator-wireframe>
      </velt-comments-sidebar-status-dropdown-trigger-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar that represents the List of Comments in the Sidebar

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/list.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.List>
          <VeltCommentsSidebarWireframe.List.Item>
              <VeltCommentsSidebarWireframe.List.Item.Group />
              <VeltCommentsSidebarWireframe.List.Item.DialogContainer />
          </VeltCommentsSidebarWireframe.List.Item>
      </VeltCommentsSidebarWireframe.List>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-list-wireframe>
          <velt-comments-sidebar-list-item-wireframe>
              <velt-comments-sidebar-list-item-group-wireframe></velt-comments-sidebar-list-item-group-wireframe>
              <velt-comments-sidebar-list-item-dialog-container-wireframe></velt-comments-sidebar-list-item-dialog-container-wireframe>
          </velt-comments-sidebar-list-item-wireframe>
      </velt-comments-sidebar-list-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

You can customize the Comment Dialog that appears inside the Sidebar with this subcomponent

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

You can customize the Comment Dialog that appears in the Sidebar by adding a Comment Dialog Wireframe inside this subcomponent and modifying it to your liking.

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.List.Item.DialogContainer>
          <VeltCommentDialogWireframe>
              ...
          </VeltCommentDialogWireframe>
      </VeltCommentsSidebarWireframe.List.Item.DialogContainer> 
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-list-item-dialog-container-wireframe>
          <velt-comment-dialog-wireframe>
          ...
          </velt-comment-dialog-wireframe>
      </velt-comments-sidebar-list-item-dialog-container-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar List that represents the Group

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.List.Item.Group>
          <VeltCommentsSidebarWireframe.List.Item.Group.Name />
          <VeltCommentsSidebarWireframe.List.Item.Group.Count />
          <VeltCommentsSidebarWireframe.List.Item.Group.Arrow />
      </VeltCommentsSidebarWireframe.List.Item.Group>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-list-item-group-wireframe>
          <velt-comments-sidebar-list-item-group-name-wireframe></velt-comments-sidebar-list-item-group-name-wireframe>
          <velt-comments-sidebar-list-item-group-count-wireframe></velt-comments-sidebar-list-item-group-count-wireframe>
          <velt-comments-sidebar-list-item-group-arrow-wireframe></velt-comments-sidebar-list-item-group-arrow-wireframe>
      </velt-comments-sidebar-list-item-group-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar that represents the Composer that appears in Page Mode.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/sidebar-composer.png)

<Note>This subcomponent does not support children </Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.PageModeComposer />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-page-mode-composer-wireframe></velt-comments-sidebar-page-mode-composer-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null



<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.ResetFilterButton />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-reset-filter-button-wireframe></velt-comments-sidebar-reset-filter-button-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The button that is used to open the Comments Sidebar panel.

<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default sidebar button looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/sidebar-button-light.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltSidebarButtonWireframe>
          <VeltSidebarButtonWireframe.Icon />
          <VeltSidebarButtonWireframe.CommentsCount />
      </VeltSidebarButtonWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-sidebar-button-wireframe>
          <velt-sidebar-button-icon-wireframe></velt-sidebar-button-icon-wireframe>
          <velt-sidebar-button-comments-count-wireframe></velt-sidebar-button-comments-count-wireframe>
      </velt-sidebar-button-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltSidebarButton shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```jsx
    <velt-sidebar-button shadow-dom="false"></velt-sidebar-button>
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/sidebar-button-dark.png)

By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

`Default: false`

To enable Dark Mode for sidebar button:

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```js
    <VeltSidebarButton darkMode={true} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```js
    <velt-sidebar-button dark-mode="true"></velt-sidebar-button>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# null

The subcomponent on the Sidebar Button that shows the total

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/sidebar-button-count.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltSidebarButtonWireframe.CommentsCount />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-sidebar-button-comments-count-wireframe></velt-sidebar-button-comments-count-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Sidebar Button that shows the total

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/sidebar-button-icon.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltSidebarButtonWireframe.Icon />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-sidebar-button-icon-wireframe></velt-sidebar-button-icon-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Comments Sidebar that represents the Skeleton loader that appears when the Sidebar is first loading.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/sidebar-skeleton.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentsSidebarWireframe.Skeleton />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comments-sidebar-skeleton-wireframe></velt-comments-sidebar-skeleton-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null



## Variants

Here are the variants that you can use in Comments Sidebar:

*   `variant`: This is the variant for the entire Comments Sidebar.
*   `dialogVariant`: This is the variant for the Comment Dialog that appears in the Comments Sidebar.
*   `pageModeComposerVariant`: This is the variant for the Comment Composer that appears in the Comments Sidebar in page mode.
*   `focusedThreadDialogVariant`: This is the variant for the Comment Dialog that appears when a focused thread mode is enabled.

<RequestExample>
  ```jsx React / Next.js
  <VeltCommentsSidebar
    variant="sidebar1"
    dialogVariant="dialogInSidebar"
    pageModeComposerVariant="pageModeDialogInSidebar"
    focusedThreadDialogVariant="focusedThreadDialogInSidebar"
  />
  ```

  ```HTML HTML
  <velt-comments-sidebar
    variant="sidebar1"
    dialog-variant="dialogInSidebar"
    page-mode-composer-variant="pageModeDialogInSidebar"
    focused-thread-dialog-variant="focusedThreadDialogInSidebar"
  ></velt-comments-sidebar>
  ```
</RequestExample>


# Overview

The Confirmation Dialog that appears when you delete a comment annotation.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default confirmation dialog component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/confirmation-dialog.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltConfirmDialogWireframe.Title`
    *   `VeltConfirmDialogWireframe.Message`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-confirm-dialog-title-wireframe`
    *   `velt-confirm-dialog-message-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltConfirmDialogWireframe>
          <VeltConfirmDialogWireframe.Title></VeltConfirmDialogWireframe.Title>
          <VeltConfirmDialogWireframe.Message></VeltConfirmDialogWireframe.Message>
          <VeltConfirmDialogWireframe.RejectButton></VeltConfirmDialogWireframe.RejectButton>
          <VeltConfirmDialogWireframe.ApproveButton></VeltConfirmDialogWireframe.ApproveButton>
      </VeltConfirmDialogWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none">
      <velt-confirm-dialog-wireframe>
         <velt-confirm-dialog-title-wireframe></velt-confirm-dialog-title-wireframe>
         <velt-confirm-dialog-message-wireframe></velt-confirm-dialog-message-wireframe>
         <velt-confirm-dialog-reject-button-wireframe></velt-confirm-dialog-reject-button-wireframe>
         <velt-confirm-dialog-approve-button-wireframe></velt-confirm-dialog-approve-button-wireframe>
     </velt-confirm-dialog-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

ShadowDOM is not used in this component. You can apply your styling directly to the component.

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/ui-customization/features/async/comments/confirm-dialog/images/customization/confirmation-dialog-dark.png)
This component takes the dark mode property from the parent feature (eg: comments) where this used.
If the parent feature component is in dark mode, this component will also be in dark mode.


# Overview

Components that appear when using Inline Comments

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default inline comment component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/inline-comments-overview.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltInlineCommentsSectionWireframe.CommentCount`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-inline-comments-section-comment-count-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltInlineCommentsSectionWireframe>
          <VeltInlineCommentsSectionWireframe.Skeleton />
          <VeltInlineCommentsSectionWireframe.Panel>
              <VeltInlineCommentsSectionWireframe.ComposerContainer />
              <VeltInlineCommentsSectionWireframe.CommentCount />
              <VeltInlineCommentsSectionWireframe.List />
          </VeltInlineCommentsSectionWireframe.Panel>
      </VeltInlineCommentsSectionWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-inline-comments-section-wireframe>
          <velt-inline-comments-section-skeleton-wireframe></velt-inline-comments-section-skeleton-wireframe>
          <velt-inline-comments-section-panel-wireframe>
              <velt-inline-comments-section-composer-container-wireframe></velt-inline-comments-section-composer-container-wireframe>
              <velt-inline-comments-section-comment-count-wireframe></velt-inline-comments-section-comment-count-wireframe>
              <velt-inline-comments-section-list-wireframe></velt-inline-comments-section-list-wireframe>
          </velt-inline-comments-section-panel-wireframe>
      </velt-inline-comments-section-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Variants



## Pre-defined Variants

This has two pre-deinfed variants:

1.  `dialog-variant`: Use this to customize the `Comment Dialog` that appears within the `Inline Comments Section` component.
2.  `variant`: Use this to customize the entire `Inline Comments Section` component itself.

<RequestExample>
  ```jsx React / Next.js
  <VeltInlineCommentsSection
      targetInlineCommentElementId="custom-id"	
  	dialogVariant="dialog-variant-name"
      variant="inline-comment-section-variant-name"
  />

  ```

  ```HTML HTML
  <velt-inline-comments-section
      dialog-variant="dialog-variant-name"
      variant="inline-comment-section-variant-name"
  >
  </velt-inline-comments-section>
  ```
</RequestExample>


# null

The subcomponent of the Inline Comments Section that contains the Comment Count

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/inline-comments-count.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltInlineCommentsSectionWireframe.CommentCount />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-inline-comments-section-comment-count-wireframe></velt-inline-comments-section-comment-count-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Inline Comments Section that contains the Composer Container

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/inline-comments-composer.png)

You can customize the Comment Dialog that appears in the Inline Comments Section by adding a Comment Dialog Wireframe inside this subcomponent and modifying it to your liking.

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltInlineCommentsSectionWireframe.ComposerContainer>
          <VeltCommentDialogWireframe.Composer>
          ...Custom Composer
          </VeltCommentDialogWireframe.Composer>
      </VeltInlineCommentsSectionWireframe.ComposerContainer>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-inline-comments-section-composer-container-wireframe>
          <velt-comment-dialog-composer-wireframe>
              ...Custom Composer
          </velt-comment-dialog-composer-wireframe>
      </velt-inline-comments-section-composer-container-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Inline Comments Section that contains the List

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/inline-comments-list.png)

You can customize the Comment Dialog that appears in the List of the Inline Comments Section by adding a Comment Dialog Wireframe inside this subcomponent and modifying it to your liking.

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltInlineCommentsSectionWireframe.List>
          <VeltCommentDialogWireframe>
          ...Custom Dialog
          </VeltCommentDialogWireframe>
      </VeltInlineCommentsSectionWireframe.List>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-inline-comments-section-list-wireframe>
          <velt-comment-dialog-wireframe>
              ...Custom Dialog
          </velt-comment-dialog-wireframe>
      </velt-inline-comments-section-list-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Inline Comments Section that contains the Panel

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/ui-customization/features/async/comments/inline-comments-section/subcomponents/panel/images/inline-comments-breakdown.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltInlineCommentsSectionWireframe.Panel>
          <VeltInlineCommentsSectionWireframe.ComposerContainer />
          <VeltInlineCommentsSectionWireframe.CommentCount />
          <VeltInlineCommentsSectionWireframe.List />
      </VeltInlineCommentsSectionWireframe.Panel>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-inline-comments-section-panel-wireframe>
          <velt-inline-comments-section-composer-container-wireframe></velt-inline-comments-section-composer-container-wireframe>
          <velt-inline-comments-section-comment-count-wireframe></velt-inline-comments-section-comment-count-wireframe>
          <velt-inline-comments-section-list-wireframe></velt-inline-comments-section-list-wireframe>
      </velt-inline-comments-section-panel-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent of the Inline Comments Section that contains the Skeleton loader that appears when the Inline Comments Section is first loading.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default skeleton subcomponent looks like:
![](https://mintlify.s3-us-west-1.amazonaws.com/velt/ui-customization/features/async/comments/inline-comments-section/subcomponents/images/inline-comments-loading.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltInlineCommentsSectionWireframe.Skeleton />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-inline-comments-section-skeleton-wireframe></velt-inline-comments-section-skeleton-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview



<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltMultiThreadCommentDialogWireframe>
          <VeltMultiThreadCommentDialogWireframe.CommentCount />
          <VeltMultiThreadCommentDialogWireframe.MinimalFilterDropdown />
          <VeltMultiThreadCommentDialogWireframe.MinimalActionsDropdown />
          <VeltMultiThreadCommentDialogWireframe.NewThreadButton />
          <VeltMultiThreadCommentDialogWireframe.CloseButton />
          <VeltMultiThreadCommentDialogWireframe.List />
          <VeltMultiThreadCommentDialogWireframe.ResetFilterButton />
          <VeltMultiThreadCommentDialogWireframe.ComposerContainer />
      </VeltMultiThreadCommentDialogWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-multi-thread-comment-dialog-wireframe>
          <velt-multi-thread-comment-dialog-comment-count-wireframe></velt-multi-thread-comment-dialog-comment-count-wireframe>
          <velt-multi-thread-comment-dialog-minimal-filter-dropdown-wireframe></velt-multi-thread-comment-dialog-minimal-filter-dropdown-wireframe>
          <velt-multi-thread-comment-dialog-minimal-actions-dropdown-wireframe></velt-multi-thread-comment-dialog-minimal-actions-dropdown-wireframe>
          <velt-multi-thread-comment-dialog-new-thread-button-wireframe></velt-multi-thread-comment-dialog-new-thread-button-wireframe>
          <velt-multi-thread-comment-dialog-close-button-wireframe></velt-multi-thread-comment-dialog-close-button-wireframe>
          <velt-multi-thread-comment-dialog-list-wireframe></velt-multi-thread-comment-dialog-list-wireframe>
          <velt-multi-thread-comment-dialog-reset-filter-button-wireframe></velt-multi-thread-comment-dialog-reset-filter-button-wireframe>
          <velt-multi-thread-comment-dialog-composer-container-wireframe></velt-multi-thread-comment-dialog-composer-container-wireframe>
      </velt-multi-thread-comment-dialog-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The persistent comment mode banner that appears when persistent mode is enabled and user is adding a comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltPersistentCommentModeWireframe>
          <VeltPersistentCommentModeWireframe.CloseButton />
          <VeltPersistentCommentModeWireframe.Label>
              <VeltPersistentCommentModeWireframe.Label.Public />
              <VeltPersistentCommentModeWireframe.Label.Private />
          </VeltPersistentCommentModeWireframe.Label>
      </VeltPersistentCommentModeWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-persistent-comment-mode-wireframe>
         <velt-persistent-comment-mode-close-button-wireframe></velt-persistent-comment-mode-close-button-wireframe>
         <velt-persistent-comment-mode-label-wireframe>
             <velt-persistent-comment-mode-label-public-wireframe></velt-persistent-comment-mode-label-public-wireframe>
             <velt-persistent-comment-mode-label-private-wireframe></velt-persistent-comment-mode-label-private-wireframe>
         </velt-persistent-comment-mode-label-wireframe>
     </velt-persistent-comment-mode-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview



<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

This component is a thin wrapper around the [Comment Dialog Composer](/ui-customization/features/async/comments/comment-dialog/subcomponents/composer/overview) component.

## Default Component

Here's how the default comment composer component looks like:
![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-sub-7.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentComposerWireframe>
          <VeltCommentDialogWireframe.Composer>
              ... Custom Composer Wirefame
          </VeltCommentDialogWireframe.Composer>
      </VeltCommentComposerWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-composer-wireframe>
          <velt-comment-dialog-composer-wireframe>
              ... custom composer wireframe
          </velt-comment-dialog-composer-wireframe>
      </velt-comment-composer-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentComposer shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-composer shadow-dom="false"></velt-comment-composer>
    ```
  </Tab>
</Tabs>

## Dark Mode

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentComposer darkMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-composer dark-mode="true"></velt-comment-composer>
    ```
  </Tab>
</Tabs>


# Variants



*   Define variants for the entire Comment Composer component. This will enable you to show different Composer UI in different parts of your app.
*   Alternatively, define a variant for the Comment Dialog component and use it here. This will enable you to show different Comment Dialog UI on the DOM vs here.
*   Learn more about how to define and use variants [here](/ui-customization/variants).

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentComposer 
      variant="component-variant" 
      dialogVariant="dialog-variant"
    />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-composer 
      dialog-variant="dialog-variant"
      variant="component-variant"
    ></velt-comment-composer> 
    ```
  </Tab>
</Tabs>


# Overview

The Pin that appears on the DOM when you place a Comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default comment pin component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-pin-light.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/comment-pin-all-states-light.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentPinWireframe>
          {/* Ghost Comment Indicator */}
          <VeltCommentPinWireframe.GhostCommentIndicator/>
          {/* Index */}
          <VeltCommentPinWireframe.Index/>
          {/* Private Comment Indicator */}
          <VeltCommentPinWireframe.PrivateCommentIndicator/>
          {/* Triangle */}
          <VeltCommentPinWireframe.Triangle/>
          {/* Unread Comment Indicator */}
          <VeltCommentPinWireframe.UnreadCommentIndicator/>
      </VeltCommentPinWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-pin-wireframe>
          <!-- Ghost Comment Indicator -->
          <velt-comment-pin-ghost-comment-indicator-wireframe></velt-comment-pin-ghost-comment-indicator-wireframe>
          <!-- Index -->
          <velt-comment-pin-index-wireframe></velt-comment-pin-index-wireframe>
          <!-- Private Comment Indicator -->
          <velt-comment-pin-private-comment-indicator-wireframe></velt-comment-pin-private-comment-indicator-wireframe>
          <!-- Triangle -->
          <velt-comment-pin-triangle-wireframe></velt-comment-pin-triangle-wireframe>
          <!-- Unread Comment Indicator -->
          <velt-comment-pin-unread-comment-indicator-wireframe></velt-comment-pin-unread-comment-indicator-wireframe>
      </velt-comment-pin-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Variants



*   Define variants for the `Velt Comment Pin` component. This is useful for customizing how the pin looks on different elements like charts, tables, etc.
*   Learn more about how to define and use variants [here](/ui-customization/variants).

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentPin variant="CUSTOM_VARIANT" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-pin variant="CUSTOM_VARIANT"></velt-comment-pin>
    ```
  </Tab>
</Tabs>


# Overview



<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

This component is a thin wrapper around the Comment Dialog component.

## Default Component

Here's how the default comment thread component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-1.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-comment-dialog-2.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltCommentThreadWireframe>
          <VeltCommentDialogWireframe />
      </VeltCommentThreadWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-comment-thread-wireframe>
          <velt-comment-dialog-wireframe>
          </velt-comment-dialog-wireframe>
      </velt-comment-thread-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentThread shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-thread shadow-dom="false"></velt-comment-thread>
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/dark-light-mode.png)

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltCommentThread darkMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-thread dark-mode="true"></velt-comment-thread>
    ```
  </Tab>
</Tabs>


# Variants



*   Define variants for the entire Comment Thread component. This will enable you to show different Thread UI in different parts of your app.
*   Alternatively, define a variant for the Comment Dialog component and use it here. This will enable you to show different Comment Dialog UI on the DOM vs here.
*   Learn more about how to define and use variants [here](/ui-customization/variants).

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentThread 
      variant="component-variant" 
      dialogVariant="dialog-variant"
    />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comment-thread 
      dialog-variant="dialog-variant"
      variant="component-variant"
    ></velt-comment-thread> 
    ```
  </Tab>
</Tabs>


# Overview

The Comment Tool that appears when you highlight some text.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default text comment tool component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/text-comment-light.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltTextCommentToolWireframe>
          # Your custom element
      </VeltTextCommentToolWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-text-comment-tool-wireframe>
          # Your custom element
      </velt-text-comment-tool-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltComments shadowDom={false} textCommentToolShadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```jsx
    <velt-comments shadow-dom="false" text-comment-tool-shadow-dom="false"></velt-comments>
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/velt-text-comment-1.png)
By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

`Default: false`

Below are the examples to enable Dark Mode for text comment tool.

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```js
    <VeltComments textCommentToolDarkMode={true} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```js
    <velt-comments text-comment-tool-dark-mode="true"></velt-comments>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# Overview

The Toolbar that appears when you highlight some text

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default text comment toolbar component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/text-comment-toolbar-light.png)

There are 4 `Subcomponents` within the `Text Comment Toolbar` component.

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltTextCommentToolbarWireframe>
          <VeltTextCommentToolbarWireframe.CommentAnnotation />
          <VeltTextCommentToolbarWireframe.Divider />
          <VeltTextCommentToolbarWireframe.Copywriter />
          <VeltTextCommentToolbarWireframe.Generic />
      </VeltTextCommentToolbarWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-text-comment-toolbar-wireframe>
          <velt-text-comment-toolbar-comment-annotation-wireframe></velt-text-comment-toolbar-comment-annotation-wireframe>
          <velt-text-comment-toolbar-divider-wireframe></velt-text-comment-toolbar-divider-wireframe>
          <velt-text-comment-toolbar-copywriter-wireframe></velt-text-comment-toolbar-copywriter-wireframe>
          <velt-text-comment-toolbar-generic-wireframe></velt-text-comment-toolbar-generic-wireframe>
      </velt-text-comment-toolbar-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltComments shadowDom={false} textCommentToolbarShadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```jsx
    <velt-comments shadow-dom="false" text-comment-toolbar-shadow-dom="false"></velt-comments>
    ```
  </Tab>
</Tabs>

## Dark Mode

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/text-comment-toolbar-dark.png)

By default, all components are in Light Mode, but there are several properties and methods to enable Dark Mode.

`Default: false`

Below are the examples to enable Dark Mode for text comment toolbar.

<Tabs>
  <Tab title="React / Next.js">
    ### Example

    ```jsx
    <VeltComments textCommentToolbarDarkMode={true} />
    ```

    ### API methods

    ```jsx
    const commentElement = client.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ### Example

    ```jsx
    <velt-comments text-comment-toolbar-dark-mode="true"></velt-comments>
    ```

    ### API methods

    ```jsx
    const commentElement = Velt.getCommentElement();
    commentElement.enableDarkMode();
    commentElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# null

The subcomponent on the Text Comment Toolbar that is used to add a new Text Comment.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/text-comment-toolbar-sub-1.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltTextCommentToolbarWireframe.CommentAnnotation />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-text-comment-toolbar-comment-annotation-wireframe></velt-text-comment-toolbar-comment-annotation-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Text Comment Toolbar that is used to rewrite text on the page using AI.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/text-comment-toolbar-sub-3.png)

<Note>This subcomponent does not support children</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltTextCommentToolbarWireframe.Copywriter />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-text-comment-toolbar-copywriter-wireframe></velt-text-comment-toolbar-copywriter-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Text Comment Toolbar that is used to divide other subcomponents in the UI using a thin line.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/text-comment-toolbar-sub-2.png)

<Note>This subcomponent does not support children</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltTextCommentToolbarWireframe.Divider />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-text-comment-toolbar-divider-wireframe></velt-text-comment-toolbar-divider-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The subcomponent on the Text Comment Toolbar that is used to query ChatGPT.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Subcomponent

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/text-comment-toolbar-sub-4.png)

<Note>This subcomponent does not support children</Note>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltTextCommentToolbarWireframe.Generic />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-text-comment-toolbar-generic-wireframe></velt-text-comment-toolbar-generic-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The Notification Panel contains all notifications within the current organization. It appears when you click the notification tool or embed it directly on a page.

<Note>
  We recommend that you familiarize yourselves with [Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications-overview.png)

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications-overview-breakdown.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe>
          <VeltNotificationsPanelWireframe.Title />
          <VeltNotificationsPanelWireframe.ReadAllButton />

          <VeltNotificationsPanelWireframe.Skeleton />

          {/* Header with Tabs */}
          <VeltNotificationsPanelWireframe.Header />

          {/* Main Content */}
          <VeltNotificationsPanelWireframe.Content>
          
              {/* For You Tab */}
              <VeltNotificationsPanelWireframe.Content.ForYou />

              {/* Documents Tab */}
              <VeltNotificationsPanelWireframe.Content.Documents />

              {/* People Tab */}
              <VeltNotificationsPanelWireframe.Content.People />

              {/* All Tab */}
              <VeltNotificationsPanelWireframe.Content.All />

          </VeltNotificationsPanelWireframe.Content>

      </VeltNotificationsPanelWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-wireframe>
          <velt-notifications-panel-title-wireframe></velt-notifications-panel-title-wireframe>
          <velt-notifications-panel-read-all-button-wireframe></velt-notifications-panel-read-all-button-wireframe>
          
          <velt-notifications-panel-skeleton-wireframe></velt-notifications-panel-skeleton-wireframe>
          
          <!-- Header with Tabs -->
          <velt-notifications-panel-header-wireframe></velt-notifications-panel-header-wireframe>
          
          <!-- Main Content -->
          <velt-notifications-panel-content-wireframe>
                  <!-- For You Tab -->
                  <velt-notifications-panel-content-for-you-wireframe></velt-notifications-panel-content-for-you-wireframe>
      
                  <!-- Documents Tab -->
                  <velt-notifications-panel-content-documents-wireframe></velt-notifications-panel-content-documents-wireframe>
      
                  <!-- People Tab -->
                  <velt-notifications-panel-content-people-wireframe></velt-notifications-panel-content-people-wireframe>

                  <!-- All Tab -->
                  <velt-notifications-panel-content-all-wireframe></velt-notifications-panel-content-all-wireframe>
          </velt-notifications-panel-content-wireframe>
              
      </velt-notifications-panel-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltNotificationsPanel shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-notifications-panel shadow-dom="false"></velt-notifications-panel>
    ```
  </Tab>
</Tabs>

## Dark Mode

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltNotificationsPanel darkMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-notifications-panel dark-mode="true"></velt-notifications-panel>
    ```
  </Tab>
</Tabs>


# null

Common Content List component used within all the tab content sections. This renders the list of notifications. You can customize it for all tabs using this or customize it individually within each tab.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications-item.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltNotificationsPanelWireframe.Content.List.Item.Avatar`
    *   `VeltNotificationsPanelWireframe.Content.List.Item.Headline`
    *   `VeltNotificationsPanelWireframe.Content.List.Item.Body`
    *   `VeltNotificationsPanelWireframe.Content.List.Item.FileName`
    *   `VeltNotificationsPanelWireframe.Content.List.Item.Time`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-notifications-panel-content-list-item-avatar-wireframe`
    *   `velt-notifications-panel-content-list-item-headline-wireframe`
    *   `velt-notifications-panel-content-list-item-body-wireframe`
    *   `velt-notifications-panel-content-list-item-file-name-wireframe`
    *   `velt-notifications-panel-content-list-item-time-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Content.List>
          <VeltNotificationsPanelWireframe.Content.List.Item>
              <VeltNotificationsPanelWireframe.Content.List.Item.Avatar />
              <VeltNotificationsPanelWireframe.Content.List.Item.Unread />
              <VeltNotificationsPanelWireframe.Content.List.Item.Headline />
              <VeltNotificationsPanelWireframe.Content.List.Item.Body />
              <VeltNotificationsPanelWireframe.Content.List.Item.FileName />
              <VeltNotificationsPanelWireframe.Content.List.Item.Time />
          </VeltNotificationsPanelWireframe.Content.List.Item>
      </VeltNotificationsPanelWireframe.Content.List>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-content-list-wireframe>
          <velt-notifications-panel-content-list-item-wireframe>
              <velt-notifications-panel-content-list-item-avatar-wireframe></velt-notifications-panel-content-list-item-avatar-wireframe>
              <velt-notifications-panel-content-list-item-unread-wireframe></velt-notifications-panel-content-list-item-unread-wireframe>
              <velt-notifications-panel-content-list-item-headline-wireframe></velt-notifications-panel-content-list-item-headline-wireframe>
              <velt-notifications-panel-content-list-item-body-wireframe></velt-notifications-panel-content-list-item-body-wireframe>
              <velt-notifications-panel-content-list-item-file-name-wireframe></velt-notifications-panel-content-list-item-file-name-wireframe>
              <velt-notifications-panel-content-list-item-time-wireframe></velt-notifications-panel-content-list-item-time-wireframe>
          </velt-notifications-panel-content-list-item-wireframe>
      </velt-notifications-panel-content-list-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

This contains the main body of the Notifications Panel with the content of each tab.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications-content.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Content>
          
          {/* For You Tab */}
          <VeltNotificationsPanelWireframe.Content.ForYou />

          {/* Documents Tab */}
          <VeltNotificationsPanelWireframe.Content.Documents />

          {/* People Tab */}
          <VeltNotificationsPanelWireframe.Content.People />

          {/* All Tab */}
          <VeltNotificationsPanelWireframe.Content.All />

      </VeltNotificationsPanelWireframe.Content>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-content-wireframe>
          <!-- For You Tab -->
          <velt-notifications-panel-content-for-you-wireframe></velt-notifications-panel-content-for-you-wireframe>

          <!-- Documents Tab -->
          <velt-notifications-panel-content-documents-wireframe></velt-notifications-panel-content-documents-wireframe>

          <!-- People Tab -->
          <velt-notifications-panel-content-people-wireframe></velt-notifications-panel-content-people-wireframe>

          <!-- All Tab -->
          <velt-notifications-panel-content-all-wireframe></velt-notifications-panel-content-all-wireframe>
      </velt-notifications-panel-content-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

All Tab content that contains it's notifications.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications_all_tab_content.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Content.All>
       <VeltNotificationsPanelWireframe.Content.All.List>
         <VeltNotificationsPanelWireframe.Content.All.List.Item>
           <VeltNotificationsPanelWireframe.Content.All.List.Item.Label />
           <VeltNotificationsPanelWireframe.Content.All.List.Item.Content>
             {/* Refer to the Common Content List section for this definition */}
             <VeltNotificationsPanelWireframe.Content.List />
             <VeltNotificationsPanelWireframe.Content.LoadMore />
           </VeltNotificationsPanelWireframe.Content.All.List.Item.Content>
         </VeltNotificationsPanelWireframe.Content.All.List.Item>
       </VeltNotificationsPanelWireframe.Content.All.List>
       {/* This only renders when there are no unread notifications */}
       <VeltNotificationsPanelWireframe.Content.AllReadContainer />
     </VeltNotificationsPanelWireframe.Content.All>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-content-all-wireframe>
          <velt-notifications-panel-content-all-list-wireframe>
              <velt-notifications-panel-content-all-list-item-wireframe>
                  <velt-notifications-panel-content-all-list-item-label-wireframe></velt-notifications-panel-content-all-list-item-label-wireframe>
                  <velt-notifications-panel-content-all-list-item-content-wireframe>
                      <!-- Refer to the Common Content List section for this definition -->
                      <velt-notifications-panel-content-list-wireframe></velt-notifications-panel-content-list-wireframe>
                      <velt-notifications-panel-content-load-more-wireframe></velt-notifications-panel-content-load-more-wireframe>
                  </velt-notifications-panel-content-all-list-item-content-wireframe>
              </velt-notifications-panel-content-all-list-item-wireframe>
          </velt-notifications-panel-content-all-list-wireframe>
          <!-- This only renders when there are no unread notifications -->
          <velt-notifications-panel-content-all-read-container-wireframe></velt-notifications-panel-content-all-read-container-wireframe>
      </velt-notifications-panel-content-all-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

Document tab content that contains it's notifications.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications_documents_tab_content.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltNotificationsPanelWireframe.Content.Documents.List.Item.Name`
    *   `VeltNotificationsPanelWireframe.Content.Documents.List.Item.Count`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-notifications-panel-content-documents-list-item-name-wireframe`
    *   `velt-notifications-panel-content-documents-list-item-count-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Content.Documents>
          <VeltNotificationsPanelWireframe.Content.Documents.List>
              <VeltNotificationsPanelWireframe.Content.Documents.List.Item>
                  <VeltNotificationsPanelWireframe.Content.Documents.List.Item.Unread />
                  <VeltNotificationsPanelWireframe.Content.Documents.List.Item.Name />
                  <VeltNotificationsPanelWireframe.Content.Documents.List.Item.Count />
                  <VeltNotificationsPanelWireframe.Content.Documents.List.Item.Content>
                      {/* Refer to the Common Content List section for this definition */}
                      <VeltNotificationsPanelWireframe.Content.List />
                      <VeltNotificationsPanelWireframe.Content.LoadMore />
                  </VeltNotificationsPanelWireframe.Content.Documents.List.Item.Content>
              </VeltNotificationsPanelWireframe.Content.Documents.List.Item>
          </VeltNotificationsPanelWireframe.Content.Documents.List>
          {/* This only renders when there are no unread notifications */}
          <VeltNotificationsPanelWireframe.Content.AllReadContainer />
      </VeltNotificationsPanelWireframe.Content.Documents>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-content-documents-wireframe>
          <velt-notifications-panel-content-documents-list-wireframe>
              <velt-notifications-panel-content-documents-list-item-wireframe>
                  <velt-notifications-panel-content-documents-list-item-unread-wireframe></velt-notifications-panel-content-documents-list-item-unread-wireframe>
                  <velt-notifications-panel-content-documents-list-item-name-wireframe></velt-notifications-panel-content-documents-list-item-name-wireframe>
                  <velt-notifications-panel-content-documents-list-item-count-wireframe></velt-notifications-panel-content-documents-list-item-count-wireframe>
                  <velt-notifications-panel-content-documents-list-item-content-wireframe>
                      <!-- Refer to the Common Content List section for this definition -->
                      <velt-notifications-panel-content-list-wireframe></velt-notifications-panel-content-list-wireframe>
                      <velt-notifications-panel-content-load-more-wireframe></velt-notifications-panel-content-load-more-wireframe>
                  </velt-notifications-panel-content-documents-list-item-content-wireframe>
              </velt-notifications-panel-content-documents-list-item-wireframe>
          </velt-notifications-panel-content-documents-list-wireframe>
          <!-- This only renders when there are no unread notifications -->
          <velt-notifications-panel-content-all-read-container-wireframe></velt-notifications-panel-content-all-read-container-wireframe>
      </velt-notifications-panel-content-documents-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

For You tab content that contains it's notifications.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications_for_you_tab_content.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Content.ForYou>
          {/* Refer to the Common Content List section for this definition */}
          <VeltNotificationsPanelWireframe.Content.List />
          <VeltNotificationsPanelWireframe.Content.LoadMore />
          {/* This only renders when there are no unread notifications */}
          <VeltNotificationsPanelWireframe.Content.AllReadContainer />
      </VeltNotificationsPanelWireframe.Content.ForYou>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-content-for-you-wireframe>
          <!-- Refer to the Common Content List section for this definition -->
          <velt-notifications-panel-content-list-wireframe></velt-notifications-panel-content-list-wireframe>
          <velt-notifications-panel-content-load-more-wireframe></velt-notifications-panel-content-load-more-wireframe>
          <!-- This only renders when there are no unread notifications -->
          <velt-notifications-panel-content-all-read-container-wireframe></velt-notifications-panel-content-all-read-container-wireframe>
      </velt-notifications-panel-content-for-you-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

People tab content that contains it's notifications.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications_people_tab_content.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltNotificationsPanelWireframe.Content.People.List.Item.Avatar`
    *   `VeltNotificationsPanelWireframe.Content.People.List.Item.Name`
    *   `VeltNotificationsPanelWireframe.Content.People.List.Item.Count`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-notifications-panel-content-people-list-item-avatar-wireframe`
    *   `velt-notifications-panel-content-people-list-item-name-wireframe`
    *   `velt-notifications-panel-content-people-list-item-count-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Content.People>
          <VeltNotificationsPanelWireframe.Content.People.List>
              <VeltNotificationsPanelWireframe.Content.People.List.Item>
                  <VeltNotificationsPanelWireframe.Content.People.List.Item.Avatar />
                  <VeltNotificationsPanelWireframe.Content.People.List.Item.Name />
                  <VeltNotificationsPanelWireframe.Content.People.List.Item.Count />
                  <VeltNotificationsPanelWireframe.Content.People.List.Item.Content>
                      {/* Refer to the Common Content List section for this definition */}
                      <VeltNotificationsPanelWireframe.Content.List />
                      <VeltNotificationsPanelWireframe.Content.LoadMore />
                  </VeltNotificationsPanelWireframe.Content.People.List.Item.Content>
              </VeltNotificationsPanelWireframe.Content.People.List.Item>
          </VeltNotificationsPanelWireframe.Content.People.List>
          {/* This only renders when there are no unread notifications */}
          <VeltNotificationsPanelWireframe.Content.AllReadContainer />
      </VeltNotificationsPanelWireframe.Content.People>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-content-people-wireframe>
          <velt-notifications-panel-content-people-list-wireframe>
              <velt-notifications-panel-content-people-list-item-wireframe>
                  <velt-notifications-panel-content-people-list-item-avatar-wireframe></velt-notifications-panel-content-people-list-item-avatar-wireframe>
                  <velt-notifications-panel-content-people-list-item-name-wireframe></velt-notifications-panel-content-people-list-item-name-wireframe>
                  <velt-notifications-panel-content-people-list-item-count-wireframe></velt-notifications-panel-content-people-list-item-count-wireframe>
                  <velt-notifications-panel-content-people-list-item-content-wireframe>
                      <!-- Refer to the Common Content List section for this definition -->
                      <velt-notifications-panel-content-list-wireframe></velt-notifications-panel-content-list-wireframe>
                      <velt-notifications-panel-content-load-more-wireframe></velt-notifications-panel-content-load-more-wireframe>
                  </velt-notifications-panel-content-people-list-item-content-wireframe>
              </velt-notifications-panel-content-people-list-item-wireframe>
          </velt-notifications-panel-content-people-list-wireframe>
          <!-- This only renders when there are no unread notifications -->
          <velt-notifications-panel-content-all-read-container-wireframe></velt-notifications-panel-content-all-read-container-wireframe>
      </velt-notifications-panel-content-people-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

This contains all the tabs that are present in the Notifications Panel Header

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications-tab.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Header>
          <VeltNotificationsPanelWireframe.Header.TabForYou />
          <VeltNotificationsPanelWireframe.Header.TabDocuments />
          <VeltNotificationsPanelWireframe.Header.TabPeople />
          <VeltNotificationsPanelWireframe.Header.TabAll />
      </VeltNotificationsPanelWireframe.Header>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-header-wireframe>
          <velt-notifications-panel-header-tab-for-you-wireframe></velt-notifications-panel-header-tab-for-you-wireframe>
          <velt-notifications-panel-header-tab-documents-wireframe></velt-notifications-panel-header-tab-documents-wireframe>
          <velt-notifications-panel-header-tab-people-wireframe></velt-notifications-panel-header-tab-people-wireframe>
          <velt-notifications-panel-header-tab-all-wireframe></velt-notifications-panel-header-tab-all-wireframe>
      </velt-notifications-panel-header-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

This button marks all notifications as read.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications-read-all-button.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.ReadAllButton />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-read-all-button-wireframe></velt-notifications-panel-read-all-button-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# null

The component that displays the title of the Notification Panel.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notifications-title.png)

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsPanelWireframe.Title />
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-panel-title-wireframe></velt-notifications-panel-title-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Overview

The button that opens or closes the notification panel.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

## Default Component

Here's how the default notification tool component looks like:

![](https://mintlify.s3-us-west-1.amazonaws.com/velt/images/customization/notification-tool-dark.png)

## Subcomponents that don't support children

<Tabs>
  <Tab title="React / Next.js">
    *   `VeltNotificationsToolWireframe.UnreadCount`
  </Tab>

  <Tab title="Other Frameworks">
    *   `velt-notifications-tool-unread-count-wireframe`
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltNotificationsToolWireframe>
          <VeltNotificationsToolWireframe.Icon />
          <VeltNotificationsToolWireframe.UnreadIcon />
          <VeltNotificationsToolWireframe.UnreadCount />
          <VeltNotificationsToolWireframe.Label />
      </VeltNotificationsToolWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-notifications-tool-wireframe>
          <velt-notifications-tool-icon-wireframe></velt-notifications-tool-icon-wireframe>
          <velt-notifications-tool-unread-icon-wireframe></velt-notifications-tool-unread-icon-wireframe>
          <velt-notifications-tool-unread-count-wireframe></velt-notifications-tool-unread-count-wireframe>
          <velt-notifications-tool-label-wireframe></velt-notifications-tool-label-wireframe>
      </velt-notifications-tool-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

### Example

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltNotificationsTool shadowDom={false} panelShadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-notifications-tool shadow-dom="false" panel-shadow-dom="false"></velt-notifications-tool>
    ```
  </Tab>
</Tabs>

## Dark Mode

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    ```js
    <VeltNotificationsTool darkMode={true} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js
    <velt-notifications-tool dark-mode="true"></velt-notifications-tool>
    ```
  </Tab>
</Tabs>


# null



You can define and use [variants](/ui-customization/variants) for the Notification Tool or the Notification Panel.

1.  `variant`: For the Notification Tool.
2.  `panelVariant`: For the Notification Panel.

<RequestExample>
  ```jsx React / Next.js
  <VeltNotificationsTool variant='tool1' panelVariant='panel1'/>
  ```

  ```html HTML
  <velt-notifications-tool variant='tool1' panel-variant='panel1'/>
  ```
</RequestExample>


# Overview

This component is used to render the reaction tool and all the reactions.

<Note>
  We recommend that you familiarize yourselves with [UI Customization Concepts](/ui-customization/overview) before attempting to modify any components.
</Note>

{/* ## Default Component

Here's how the default component looks like: */}

<RequestExample>
  ```jsx React / Next.js
  <VeltWireframe>
      <VeltInlineReactionsSectionWireframe>
         <VeltInlineReactionsSectionWireframe.Panel>

             {/* This renders the reaction tool */}
             <VeltInlineReactionsSectionWireframe.ToolContainer>
                 <VeltReactionToolWireframe />
             </VeltInlineReactionsSectionWireframe.ToolContainer>

             {/* This renders the list of reactions added by the users */}
             <VeltInlineReactionsSectionWireframe.List>
                 <VeltReactionPinWireframe />
             </VeltInlineReactionsSectionWireframe.List>

         </VeltInlineReactionsSectionWireframe.Panel>
     </VeltInlineReactionsSectionWireframe>
  </VeltWireframe>
  ```

  ```HTML HTML
  <velt-wireframe style="display:none;">
      <velt-inline-reactions-section-wireframe>
         <velt-inline-reactions-section-panel-wireframe>

             <!-- This renders the reaction tool -->
             <velt-inline-reactions-section-tool-container-wireframe>
                 <velt-reaction-tool-wireframe></velt-reaction-tool-wireframe>
             </velt-inline-reactions-section-tool-container-wireframe>

             <!-- This renders the list of reactions added by the users -->
             <velt-inline-reactions-section-list-wireframe>
                 <velt-reaction-pin-wireframe></velt-reaction-pin-wireframe>
             </velt-inline-reactions-section-list-wireframe>

         </velt-inline-reactions-section-panel-wireframe>
     </velt-inline-reactions-section-wireframe>
  </velt-wireframe>
  ```
</RequestExample>


# Styling



## Disable ShadowDOM

*   By default, ShadowDOM is used to ensure that your app's CSS does not interfere with the styling of the SDK components.
*   Disable the shadow dom to apply your custom CSS to the component.

`Default: true`

### Example

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltInlineReactionsSection shadowDom={false} />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-inline-reactions-section shadow-dom="false"></velt-inline-reactions-section>
    ```
  </Tab>
</Tabs>

## Dark Mode

`Default: false`

<Tabs>
  <Tab title="React / Next.js">
    Using Props:

    ```js
    <VeltInlineReactionsSection darkMode={true} />
    ```

    Using API Methods:

    ```js
    const reactionElement = client.getReactionElement();
    reactionElement.enableDarkMode();
    reactionElement.disableDarkMode();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    Using Props:

    ```html
    <velt-inline-reactions-section dark-mode="true"></velt-inline-reactions-section>
    ```

    Using API Methods:

    ```js
    const reactionElement = Velt.getReactionElement();
    reactionElement.enableDarkMode();
    reactionElement.disableDarkMode();
    ```
  </Tab>
</Tabs>


# Variants



## Pre-defined Variants

The Inline Reactions has 1 pre-defined variant:

*   `inline`: This will customize the default components inside the Inline Reactions Component.

You can define your own variants and use them in different places of your app.

<RequestExample>
  ```jsx React / Next.js
   <VeltWireframe>
      <VeltInlineReactionsSection variant="inline">
      </VeltInlineReactionsSection>
  </VeltWireframe>
  ```

  ```jsx HTML
  <velt-wireframe style="display:none;">
      <velt-inline-reactions-section variant="inline">
      </velt-inline-reactions-section>
  </velt-wireframe>
  ```
</RequestExample>


# Create Your Own UI



<Tabs>
  <Tab title="React / Next.js with Hooks">
    <Steps>
      <Step title="Get the useCursorUsers Hook">
        Import the `useCursorUsers` hook.

        ```js
        import { useCursorUsers } from '@veltdev/react';
        ```

        ```js
        const cursorUsers = useCusorUsers()
        ```
      </Step>

      <Step title="Display Cursor Users List with your own UI">
        The  `cursorUsers` hook will return an array of [User objects](/api-reference/models/User).

        You can map the Cursor Users List to generate your own custom UI.

        The hook will automatically unsubscribe from the subscription when the component dismounts.

        ```jsx
        return (
          <div>
            Cursor Users: {cursorUsers.length}
            {
              cursorUsers.map( x => <div>{x.name} </div>)
            }
          </div>
        )
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="React / Next.js">
    <Steps>
      <Step title="Get the Velt client">
        Import the `useVeltClient` React hook.

        You can use this hook within your component to fetch the Velt client.

        ```js
        import { useVeltClient } from '@veltdev/react';
        ```
      </Step>

      <Step title="Create a useEffect hook">
        Create the hook with the client as a dependency.

        Make sure to check if the client is null or undefined before you use it.

        ```js
        useEffect(() => {
            if (client) {
                //...
            }
          }, [client]);
        ```
      </Step>

      <Step title="Subscribe to live cursors">
        Subscribe to the realtime Cursor users data on the current document and location.

        We will send you a new list of cursors everytime there is a change so you can build out your own cursor UI.

        ```js
        const cursorElement = client.getCursorElement();

        let subscription = cursorElement.getOnlineUsersOnCurrentDocument().subscribe((_cursorUsers) => {
        // Do something with Cursor Users list
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps>
      <Step title="Get an instance of the cursor element">
        Fetch the cursor element from the Velt client.

        ```js
        const cursorElement = window.Velt.getCursorElement();
        ```

        At this point, the Velt instance should be loaded and available to you on the window object.
      </Step>

      <Step title="Subscribe to live cursors">
        Subscribe to constant cursor changes.

        We will send you a new list of cursors everytime there is a change so you can build out your own cursor UI and logic.

        ```js
        let subscription = cursorElement.getOnlineUsersOnCurrentDocument().subscribe((cursors) => {
            // Do something with cursors list
        });
        ```

        To unsubscribe from the subscription:

        ```jsx
        subscription?.unsubscribe()
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js with Hooks
  import { useCursorUsers } from '@veltdev/react';

  export default function App() {
    const cursorUsers = useCursorUsers()

    return (
      <div>
        Cursor Users: {cursorUsers.length}
        {
          cursorUsers.map( x => <div>{x.name} </div>)
        }
      </div>
    );
  }
  ```

  ```js React / Next.js
  import { useVeltClient } from '@veltdev/react';
  import { useEffect } from 'react';

  export default function App() {

    const { client } = useVeltClient();

    useEffect(() => {
      if (client) {

        const cursorElement = client.getCursorElement();

        let subscription = cursorElement.getOnlineUsersOnCurrentDocument().subscribe((_cursorUsers) => {
          // Do something with Cursor Users list
        });

        //To unsubscribe from the subscription:
        subscription?.unsubscribe()


      }
    }, [client]);

    return (
      <>
      </>
    );
  }
  ```

  ```html HTML
  <!doctype html>
  <html lang="en">
    <head>
      <title>Cursors documentation</title>
    </head>
    <body>

      <velt-cursor></velt-cursor>

      <script>

        if (window.Velt) {

          const cursorElement = window.Velt.getCursorElement();

          let subscription = cursorElement.getOnlineUsersOnCurrentDocument().subscribe((cursors) => {
            // Do something with cursors list
          });

          //To unsubscribe from the subscription:
          subscription?.unsubscribe()


        }

      </script>

    </body>
  </html>
  ```
</RequestExample>


# Parts



<Steps>
  <Step title="Select the part you want to modify">
    We offer several parts which can be used like classes. Full list below.

    The component is encapsulated in Shadow DOM, which is isolated from the normal DOM.
  </Step>

  <Step title="Apply your CSS rules">
    Set whatever CSS rules you want.

    The part lets you target a specific element within a Shadow DOM.
  </Step>

  <Step title="Check out the table below">
    Reference the table below to see what parts we expose.

    Alternatively, you can directly inspect the component HTML to see what parts are available.

    ```java
    velt-cursor::part(label-container) {
      border-radius: 0;
    }
    ```

    <br />

    | Part Name               | What does it do?                                                                                        |
    | ----------------------- | ------------------------------------------------------------------------------------------------------- |
    | container               | Targets the root cursor container.                                                                      |
    | huddle-avatar-container | Targets the cursor avatar specific to huddle mode. You can learn more about this in the Huddle Feature. |
    | avatar-container        | Targets the avatar container specific to avatar mode.                                                   |
    | label-container         | Targets the label container.                                                                            |
    | label                   | Targets the label text.                                                                                 |
  </Step>
</Steps>


# Slots



<Tabs>
  <Tab title="React / Next.js">
    ## Add a custom icon for the cursor

    You can provide any HTML inside the cursor element.

    Just provide the correct slot attribute and the cursor icon that we use will be replaced.

    ```js
    <VeltCursor>
      <img src="..." slot="cursor" />
    </VeltCursor>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ## Add a custom icon for the cursor

    You can provide any HTML inside the cursor element.

    Just provide the correct slot attribute and the cursor icon that we use will be replaced.

    ```html
    <velt-cursor>
      <img src="..." slot="cursor" />
    </velt-cursor>
    ```
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import { VeltCursor } from '@veltdev/react';

  export default function App() {

    return (
      <>
        <VeltCursor>
          <img src="..." slot="cursor" />
        </VeltCursor>

        {/* ... */}
      </>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Cursors documentation</title>
    </head>
    <body>
      <velt-cursor>
        <img src="..." slot="cursor" />
      </velt-cursor>

      <!-- ... -->
    </body>
  </html>
  ```
</RequestExample>


# Variables



<Steps>
  <Step title="Select the Cursor component">
    You can select the Cursor component.

    Our CSS variables are set at the component level.
  </Step>

  <Step title="Modify a CSS variable">
    Set the variable to anything you want.

    We expose a set of variables so you can customize the component to better match your UI.
  </Step>

  <Step title="Check out the table below">
    Reference the table below to see what variables we expose.

    Alternatively, you can directly inspect the component CSS to see what variables are available.

    | Default                     | Default | What does it do?                                                                                       |
    | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------ |
    | `--velt-cursor-avatar-size` | 2rem    | Sets the Cursor avatar size in avatar mode.                                                            |
    | `--velt-cursor-video-size`  | 4.2rem  | Sets the Cursor video bubble size in Huddle mode. You can learn more about this in the Huddle Feature. |
  </Step>
</Steps>

```css
velt-cursor {
  --velt-cursor-avatar-size: 1.5rem;
}
```


# null



<Steps titleSize="h2">
  <Step title="Select the part you want to modify">
    We offer several parts which can be used like classes. Full list below.
    The component is encapsulated in Shadow DOM, which is isolated from the normal DOM.
  </Step>

  <Step title="Apply your CSS rules">
    Set whatever CSS rules you want.
    The part lets you target a specific element within a Shadow DOM.
  </Step>

  <Step title="Check out the table below">
    Reference the table below to see what parts we expose.
    Alternatively, you can directly inspect the component HTML to see what parts are available.

    | property           | description                               |
    | ------------------ | ----------------------------------------- |
    | `container`        | Targets the comment tool container        |
    | `button-container` | Targets the comment tool button container |
    | `button-icon`      | Targets the comment tool button SVG icon  |
  </Step>
</Steps>

<RequestExample>
  ```css Tool
  velt-huddle-tool::part(button-icon) {
    width: 1.5rem;
    height: 1.5rem;
  }
  ```
</RequestExample>


# Slots



<Tabs>
  <Tab title="React / Next.js">
    <Steps titleSize="h2">
      <Step stepNumber="1" title="Replace the Huddle Tool">
        Provide a template for the Huddle Tool.

        Target the `button` slot with your own custom template.

        ```js
        <VeltHuddleTool>
          <button slot="button">Huddle</button>
        </VeltCommentTool>
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps titleSize="h2">
      <Step stepNumber="1" title="Replace the Huddle Tool">
        Provide a template for the Huddle Tool.

        Target the `button` slot with your own custom template.

        ```html
        <velt-user-invite-tool>
          <button slot="button">Huddle</button>
        </velt-user-invite-tool>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```js React / Next.js
  import {
    VeltHuddleTool
  } from '@veltdev/react';

  export default function App() {

    return (
      <>

        <VeltHuddleTool>
          <button slot="button">Huddle</button>
        </VeltHuddleTool>

      </>
    );
  }
  ```

  ```html HTML

  <!doctype html>
  <html lang="en">
    <head>
      <title>Huddle documentation</title>
    </head>
    <body>

      <velt-user-invite-tool>
          <button slot="button">Huddle</button>
      </velt-user-invite-tool>

    </body>
  </html>
  ```
</RequestExample>


# null



To update CSS variables for the Huddle Tool, please refer to [Global Styles](/global-styles/global-styles)


# Overview



## 1. Enable/Disable Default Styling

*   When enabled, the SDK will apply default styling to the selected elements.
*   When disabled, the SDK will not apply any styling to the selected elements. You can use these classes to style the selected elements:
    *   `.velt-live-selection-on-element`: This dynamic class will be added to the selected element only when there is a user on that element.
    *   `.velt-live-selection-on-text`: This dynamic class will be added to the text node only when a user has selected that text.
*   Default: `Enabled`.

<Tabs>
  <Tab title="React / Next.js">
    ```javascript
    const selectionElement = client.getSelectionElement();

    selectionElement.enableDefaultStyling();
    selectionElement.disableDefaultStyling();
    ```

    **Custom Styling:**

    ```css
    .velt-live-selection-on-element {
      outline: 2px solid var(--velt-color);
      outline-offset: -2px;
    }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```javascript
    const selectionElement = Velt.getSelectionElement();

    selectionElement.enableDefaultStyling();
    selectionElement.disableDefaultStyling();
    ```

    **Custom Styling:**

    ```css
    .velt-live-selection-on-element {
      outline: 2px solid var(--velt-color);
      outline-offset: -2px;
    }
    ```
  </Tab>
</Tabs>


# Create Your Own UI



<Tabs>
  <Tab title="React / Next.js with Hooks">
    <Steps>
      <Step title="Get the usePresenceUsers Hook">
        Import the `usePresenceUsers` hook.

        ```js
        import { usePresenceUsers } from '@veltdev/react';
        ```

        ```js
        const presenceUsers = usePresenceUsers()
        ```
      </Step>

      <Step title="Display Presence Users List with your own UI">
        The  `usePresenceUsers` hook will return an array of [User objects](/api-reference/models/User).

        You can map the Presence Users List to generate your own custom UI.

        ```jsx
        return (
          <div>
            Presence Users: {presenceUsers.length}
            {
              presenceUsers.map( x => <div>{x.name} </div>)
            }
          </div>
        )
        ```

        The hook will automatically unsubscribe from the subscription when the component dismounts.
      </Step>
    </Steps>
  </Tab>

  <Tab title="React / Next.js">
    <Steps>
      <Step title="Get the Velt client">
        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();
        ```
      </Step>

      <Step title="Create a useEffect hook">
        Create an effect with the client as a dependency.

        Make sure to check if the client is null or undefined before you use it.

        ```js React
        useEffect(() => {
            if (client) {

              //...
            }
          }, [client]);
        ```
      </Step>

      <Step title="Subscribe to Presence users">
        Subscribe to the realtime `Presence` users data on the current document and location.

        We will send you a new list of users everytime there is a change in the status of any user, so you can build out your own `Presence` UI.

        ```js React
        useEffect(() => {
            if (client) {

              const presenceElement = client.getPresenceElement();

              let subscription = presenceElement.getOnlineUsersOnCurrentDocument().subscribe((users) => {
                // Take user list data and render your own component
              });

              // To unsubscribe from the subscription:
              subscription?.unsubscribe()


            }
          }, [client]);
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Other Frameworks">
    <Steps>
      <Step title="Subscribe to Presence users">
        Subscribe to the realtime `Presence` users data on the current document and location.

        We will send you a new list of users everytime there is a change in the status of any user, so you can build out your own `Presence` UI.

        ```js

        <script>
            if (Velt){

              const presenceElement = Velt.getPresenceElement();

              let subscription = presenceElement.getOnlineUsersOnCurrentDocument().subscribe((users) => {
                  // Take user list data and render your own component
              });

              // To unsubscribe from the subscription:
              subscription?.unsubscribe()

          
            }
        </script>
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

<RequestExample>
  ```jsx React / Next.js with Hooks
  import { usePresenceUsers } from '@veltdev/react';

  export default function App() {
    const presenceUsers = usePresenceUsers()

    return (
      <div>
        Presence Users: {presenceUsers.length}
        {
          presenceUsers.map( x => <div>{x.name} </div>)
        }
      </div>
    );
  }
  ```

  ```js React / Next.js
  import { useVeltClient } from '@veltdev/react';
  import {useEffect} from 'react';

  export default function App() {
    const { client } = useVeltClient();

    useEffect(() => {
      if (client) {

        const presenceElement = client.getPresenceElement();

        let subscription = presenceElement.getOnlineUsersOnCurrentDocument().subscribe((users) => {
          // Take users list data and render your own component
        });

        // To unsubscribe from the subscription:
        subscription?.unsubscribe()


      }
    }, [client]);

    return (
      <div className="toolbar">
        // example of rendering your own component
        // presenceUsers.map((presenceUser) => { return ( <div key={presenceUser.userId}> {/* Add custom UI code here */} </div> ) })
      </div>
    );
  }
  ```

  ```html HTML
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <title>Presence documentation</title>
      <script type="module" src="https://cdn.velt.dev/lib/sdk@latest/velt.js" onload="loadVelt()"></script>

      <script>

          async function loadVelt() {
              await Velt.init("YOUR_VELT_API_KEY");

              if (Velt){
                const presenceElement = Velt.getPresenceElement();

                let subscription = presenceElement.getOnlineUsersOnCurrentDocument().subscribe((users) => {
                    // Take users list data and render your own component
                });

                // To unsubscribe from the subscription:
                subscription?.unsubscribe()

              }
          }

          
  </script>
    </head>
    <body>
      <div class="toolbar">
        <velt-presence></velt-presence>
      </div>
    </body>
  </html>
  ```
</RequestExample>


# Parts



<Steps>
  <Step title="Select the part you want to modify">
    We offer several parts which can be used like classes. Full list below.

    The component is encapsulated in Shadow DOM, which is isolated from the normal DOM.
  </Step>

  <Step title="Apply your CSS rules">
    Set whatever CSS rules you want.

    The part lets you target a specific element within a Shadow DOM.
  </Step>

  <Step title="Check out the table below">
    Reference the table below to see what parts we expose.

    Alternatively, you can directly inspect the component HTML to see what parts are available.

    | Part Name      | What does it do?                   |
    | -------------- | ---------------------------------- |
    | tooltip        | Targets the tooltip container      |
    | tooltip-avatar | Targets the tooltip avatar         |
    | tooltip-text   | Targets the tooltip text container |
    | user-avatar    | Targets the user avatar container  |
    | more-users     | Targets the more users container   |
  </Step>
</Steps>

<RequestExample>
  ```css Parts
  velt-presence::part(user-avatar)::before {
    content: "";
    position: absolute;
    border-radius: 50%;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(45deg, rgba(255, 0, 0, 0.5), rgba(0, 255, 0, 0.5));
    pointer-events: none;
  }
  ```
</RequestExample>


# Variables



<Steps>
  <Step title="Select the Presence component">
    You can select the `Presence` component.
    Our CSS variables are set at the component level.
  </Step>

  <Step title="Modify a CSS variable">
    Set the variable to anything you want.

    We expose a set of variables so you can customize the component to better match your UI.
  </Step>

  <Step title="Check out the table below">
    Reference the table below to see what variables we expose.

    Alternatively, you can directly inspect the component CSS to see what variables are available.

    | Variable Name                        | Default (light) | Default (dark) | What does it do?                  |
    | ------------------------------------ | --------------- | -------------- | --------------------------------- |
    | --velt-presence-avatar-size          | 2rem            | 2rem           | Sets the Presence avatar size     |
    | --velt-presence-primary-text-color   | #141416         | #E5E5E9        | Sets the primary text color       |
    | --velt-presence-secondary-text-color | #777E90         | #91919C        | Sets the secondary text color     |
    | --velt-presence-tooltip-bg-color     | #FCFCFD         | #141416        | Sets the tooltip background color |
    | --velt-presence-tooltip-border-color | #E6E8EC         | #303034        | Sets the tooltip border color     |
    | --velt-pressence-more-users-color    | #D4D6DF         | #404044        | Sets the more users color         |
  </Step>
</Steps>

<RequestExample>
  ```css Variables
  velt-presence, velt-presence-tooltip {
  	// Below values are for demo purpose only,
    // you can use different avatar-size and colors according to your usecase
    --velt-presence-avatar-size: 6rem !important;
    --velt-presence-primary-text-color: red !important;
    --velt-presence-secondary-text-color: blue !important;
    --velt-presence-tooltip-bg-color: grey !important;
    --velt-presence-tooltip-border-color: red !important;
    --velt-presence-more-users-color: purple !important;
  }
  ```
</RequestExample>


# Overview



You can fully customize any Velt Component.

Here are some concepts that will help you get started. Once you know them, you can follow the [general setup guide](/ui-customization/setup) to start customizing components.

## 1. Wireframes

### a. What is a Wireframe?

*   Wireframes are powerful templates that define the structure and appearance of Velt components, serving as a blueprint for customizing their default layout and styling.
*   When you want to modify a component's appearance, you do so by altering its corresponding wireframe, which acts as a global definition determining how components will be displayed.
*   Wireframes themselves don't render directly in your application. After customizing a wireframe, you still need to place the actual Velt components in your app as usual, which will then render according to your customized wireframe definitions.

### b. How to customize a Wireframe?

*   Add the root Wireframe component.
*   Find the Wireframe component of the target Velt Component. Add it inside the root Wireframe.
*   Modify the target component wireframe by either adding custom HTML as children inside it or by adding custom styling.

### c. What can go inside a Wireframe?

You can add the following inside a Wireframe:

*   Custom HTML
*   Custom inline styling on non-Velt components
*   Velt's wireframe components

You cannot add:

*   Regular Velt Components inside a Wireframe
*   Custom inline styling on Velt components. Instead, you can wrap Velt Wireframe components in regular HTML components and style them with inline css.

### d. How to use a customized Wireframe?

After modifying a Wireframe template:

*   Place the regular Velt component in your app as usual
*   The component will render with the layout changes defined in your customized Wireframe
*   You'll see the updated appearance reflecting your template modifications

## 2. Make Layout Changes

<Warning>
  Adding children will remove the CSS for that component.
  If you add an empty wireframe with no children, it will keep its original style and children.
</Warning>

### a. Replace component layout

To completely change the layout of Velt's components, provide your own custom HTML as children within the target component's wireframe.

[Learn more](/ui-customization/customize-layout/change-default-html).

### b. Remove components

To remove a subcomponent, simply delete it from the wireframe template. This will prevent it from appearing in the rendered component.

[Learn more](/ui-customization/customize-layout/remove-existing).

### c. Reorder components

To change the order of subcomponents, simply rearrange them within the wireframe template. The rendered component will reflect this new order.

[Learn more](/ui-customization/customize-layout/change-order).

## 3. Make CSS Changes

### a. Themes

Easily customize the appearance of Velt components to match your application's design system. You can customize:

*   Border radius
*   Spacing
*   Typography
*   Colors for light and dark modes
    *   Base Colors
    *   Accent Colors
    *   Text Shades
    *   Background Shades
    *   Border Shades
    *   Status Colors (error, warning, success)
    *   Transparent colors

<Info>
  This will work even if Velt's Shadow DOM is enabled as long as you set it on the `<body>` tag.
</Info>

[Learn more](/ui-customization/customize-css/themes).

### b. Remove Shadow DOM

*   Shadow DOM is enabled by default for Velt Components. This prevents CSS from the host app affecting Velt Components.
*   Disable Shadow DOM for specific components to allow your app's CSS to style Velt Components. This affects the component and its children.

[Learn more](/ui-customization/customize-css/remove-shadow-dom).

### c. Add Dark Mode

Velt components default to light mode. To enable dark mode for specific components, use the component's designated prop or API method.

[Learn more](/ui-customization/customize-css/dark-mode).

### d. Use CSS Library

To style Velt components with a CSS library like Tailwind:

1.  Disable Shadow DOM
2.  Add the library's classes inside the wireframe or directly on the rendered Velt components. You can find the component CSS selectors by inspecting the component in the browser's developer tools.

This works just like styling any other component in your application.

<Warning>
  Do not add CSS classes directly on the Velt Wireframe components. You can add it to regular HTML elements (eg: divs) wrapped around or inside Velt Wireframe components.
</Warning>

[Learn more](/ui-customization/customize-css/use-css-library).

### e. Use Custom CSS

Same as above, you can add your classes inside the wireframes or directly on the rendered Velt components.

[Learn more](/ui-customization/customize-css/use-custom-css).

## 5. Template Variables

You can render dynamic data from these certain Data Classes inside your Velt Components Wireframe.

[Learn more](/ui-customization/template-variables).

## 6. Conditional Templates

You can conditionally show or hide parts of the Velt Component Wireframes.

[Learn more](/ui-customization/conditional-templates).

## 6. Variants

If you want to have multiple versions of customized components that you can swap between, you can use variants.

[Learn more](/ui-customization/variants)


# Overview



## 1. Add the Velt Wireframe component

*   Add the `Velt Wireframe` component to the root of your app.
*   Add the wireframes of any components you want to customize within the `Velt Wireframe` component.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    import { VeltWireframe, VeltProvider } from '@veltdev/react'
    ```

    ```jsx
    <VeltProvider>
        <VeltWireframe>
            {/* Customized component wireframes go here */}
        </VeltWireframe>
    </VeltProvider>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    <Note>
      Add the inline `style="display:none;"` CSS attribute to the `<velt-wireframe>` element to ensure it's never displayed on the DOM. While we automatically handle this, there might be instances where the wireframe becomes visible if the SDK hasn't initialized yet.
    </Note>

    ```html
    <velt-wireframe style="display:none;">
        <!-- Customized component wireframes go here -->
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

## 2. Add a component's wireframe

*   Copy the `wireframe` of the component you want to modify. You will find the wireframe for each component within it's feature documentation.
*   Place it inside the `Velt Wireframe` component.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentDialogWireframe.Header>
            <VeltCommentDialogWireframe.Status />
            <VeltCommentDialogWireframe.Priority />
            <VeltCommentDialogWireframe.Options />
            <VeltCommentDialogWireframe.CopyLink />
            <VeltCommentDialogWireframe.ResolveButton />
        </VeltCommentDialogWireframe.Header>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comment-dialog-header-wireframe>
            <velt-comment-dialog-status-wireframe></velt-comment-dialog-status-wireframe>
            <velt-comment-dialog-priority-wireframe></velt-comment-dialog-priority-wireframe>
            <velt-comment-dialog-options-wireframe></velt-comment-dialog-options-wireframe>
            <velt-comment-dialog-copy-link-wireframe></velt-comment-dialog-copy-link-wireframe>
            <velt-comment-dialog-resolve-button-wireframe></velt-comment-dialog-resolve-button-wireframe>
        </velt-comment-dialog-header-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

## 3. Customize the wireframe template

*   Modify the layout of the `wireframe` by:
    *   Adding custom HTML or CSS
    *   Reorganizing subcomponents
    *   Removing subcomponents within the template
*   To customize multiple components, simply add more Wireframes as children to the `Velt Wireframe` component.

<Warning>If you add any children to a Wireframe, the default styling of that particular component will be removed</Warning>

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentDialogWireframe.Header>
            <div>
                Custom HTML
            </div>
            <VeltCommentDialogWireframe.Status />
            <VeltCommentDialogWireframe.Priority />
            <VeltCommentDialogWireframe.Options />
            <VeltCommentDialogWireframe.CopyLink />
            <VeltCommentDialogWireframe.ResolveButton />
        </VeltCommentDialogWireframe.Header>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comment-dialog-header-wireframe>
            <div>
                Custom HTML
            </div>
            <velt-comment-dialog-status-wireframe></velt-comment-dialog-status-wireframe>
            <velt-comment-dialog-priority-wireframe></velt-comment-dialog-priority-wireframe>
            <velt-comment-dialog-options-wireframe></velt-comment-dialog-options-wireframe>
            <velt-comment-dialog-copy-link-wireframe></velt-comment-dialog-copy-link-wireframe>
            <velt-comment-dialog-resolve-button-wireframe></velt-comment-dialog-resolve-button-wireframe>
        </velt-comment-dialog-header-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

## 4. Add the component

Now that you've modified the wireframe, place the component (not the wireframe) in your app layout as you normally would

<Warning>
  The `wireframe` components are not meant to be rendered directly in your application. They serve as template definitions that specify how Velt components will render globally. After defining your wireframes, you should still place the actual Velt components in your app layout as you normally would.
</Warning>

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <div className="layout">
        <VeltComments />
    </div>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <div class="layout">
        <velt-comments></velt-comments>
    </div>
    ```
  </Tab>
</Tabs>


# Template Variables



You can render dynamic data from these Data Classes inside your Velt Components Wireframe.

## Types

There are two types of template variables:

**1. Global Template Variables:** These can be used across all components. example: the current logged in `User` is available across all components.

**2. Local Template Variables:** These are only available within the component it's data class is used. Eg: `CommentAnnotation` is only avaialable within the comment dialog container and its child components.

## Syntax

*   Refer the supported Class' fields in the `field` field of the `Velt Data` component.
*   You can refer to nested fields using the dot notation.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltData field='userContact.name' />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-data field="userContact.name"></velt-data>
    ```
  </Tab>
</Tabs>

## Global Template Variables

### **1. User**

This represents the current logged-in user. It is available across all components. Learn more about the User data class [here](/api-reference/models/User).

### **2. Unread Comment Annotation Count**

This represents the number of unread comment annotations on the current document.

### **3. Unread Comment Count**

This represents the total number of unread comments on the current document.

## Local Template Variables

### **1. UserContact**

This represents the user contact object (it has the same class as the User). It is available on the autocomplete component where the user contacts are rendered. Learn more about the UserContact data class [here](/api-reference/models/User).

### **2. CommentAnnotation**

This represents the comment thread. This is available within the comment feature components. Learn more about the CommentAnnotation data class [here](/api-reference/models/CommentAnnotation).

### **3. Comment**

This represents the message inside the thread. This is available within the comment feature components. Learn more about the Comment data class [here](/api-reference/models/Comment).

## Example Usage

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltAutocompleteOptionWireframe>
      <VeltData field='userContact.name' />
      <VeltData field='userContact.organizationName' />
    </VeltAutocompleteOptionWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```jsx
    <velt-autocomplete-option-wireframe>
      <velt-data field="userContact.name"></velt-data>
      <velt-data field="userContact.organizationName"></velt-data>
    </velt-autocomplete-option-wireframe>
    ```
  </Tab>
</Tabs>


# Variants



Variants allow you to create and use multiple customized versions of a single component in different parts of your app.

Example: You can have a customized Comment Dialog for the sidebar and another for the pin.

## 1. Define a Variant

To define a variant:

*   Add a template of the component wireframe to the `Velt Wireframe` component
*   Give it a `variant` name

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        <VeltCommentsSidebarWireframe variant="preview-page">
            #Your wireframe for the variant
        </VeltCommentsSidebarWireframe>

        <VeltCommentsSidebarWireframe variant="editor-page">
            #Your wireframe for the variant
        </VeltCommentsSidebarWireframe>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <velt-comments-sidebar-wireframe variant="preview-page">
            #Your wireframe for the variant
        </velt-comments-sidebar-wireframe>

        <velt-comments-sidebar-wireframe variant="editor-page">
            #Your wireframe for the variant
        </velt-comments-sidebar-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

## 2. Use a Variant

To apply a specific variant, simply set the `variant` prop when using the Velt component in your app.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltCommentsSidebar variant="preview-page"/>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-comments-sidebar variant="preview-page"></velt-comments-sidebar>
    ```
  </Tab>
</Tabs>

## 3. Pre-defined Variants

*   Some components have pre-defined variants with reserved names and specific functionality
*   To customize pre-defined variants:
    1.  Add the `variant` property with its reserved name to the specific Velt Wireframe component you want to customize
    2.  Provide the customized template for that variant within the wireframe component
*   Check each component's customization documentation for available pre-defined variants

For example, the `Comment Dialog` has two pre-defined `variants`:

<Tabs>
  <Tab title="React / Next.js">
    ```jsx
    <VeltWireframe>
        {/* This pre-defined variant will change the appearance of the Comment Dialog within Pin, Area, and Text comments only */}
        <VeltCommentDialogWireframe variant="dialog">
            #Your wireframe for variant
        </VeltCommentDialogWireframe>

        {/* This pre-defined variant will change the appearance of the Comment Dialog within the Sidebar only */}
        <VeltCommentDialogWireframe variant="sidebar">
            #Your wireframe for variant
        </VeltCommentDialogWireframe>
    </VeltWireframe>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html
    <velt-wireframe style="display:none;">
        <!-- This pre-defined variant will change the appearance of the Comment Dialog within Pin, Area, and Text comments only -->
        <velt-comment-dialog-wireframe variant="dialog">
            #Your wireframe for variant
        </velt-comment-dialog-wireframe>

        <!-- This pre-defined variant will change the appearance of the Comment Dialog within the Sidebar only -->
        <velt-comment-dialog-wireframe variant="sidebar">
            #Your wireframe for variant
            </velt-comment-dialog-wireframe>
    </velt-wireframe>
    ```
  </Tab>
</Tabs>

## 4. Unsupported Components

Some components currently do not support `variants`. Please check the customization docs for each component to check if `variants` are supported.


# Comments Webhooks



The `Comments` component will emit webhook notifications whenever an `action type` occurs on a comment.

To read more about how to setup webhooks with our SDK, [click here](https://docs.velt.dev/webhooks/overview).

## List of Action Types

| Action Type         | Description                                                                                                  |
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
| `newlyAdded`        | When the first comment in a thread is added                                                                  |
| `added`             | When a new comment is added. Not used for the first comment in a thread - see `newlyAdded`                   |
| `updated`           | When an existing comment content gets updated                                                                |
| `deleted`           | When an existing comments gets deleted                                                                       |
| `approved`          | When the comment is approved by the moderator. This is only applicable if you have turned on Moderator Mode. |
| `assigned`          | When a comment gets assigned to a user                                                                       |
| `statusChanged`     | When a comment has its status changed (e.g. in progress, resolved, opened)                                   |
| `priorityChanged`   | When a comment has its priority changed (e.g. P0, P1, P2 or custom set priorities)                           |
| `accessModeChanged` | When a comment is changed from private to public or vice-versa                                               |
| `accepted`          | When a comment gets accepted by the moderator. This is only applicable if you have turned on Moderator Mode. |
| `rejected`          | When a comment gets rejected by the moderator. This is only applicable if you have turned on Moderator Mode. |
| `reactionAdded`     | When a reaction is added to a comment.                                                                       |
| `reactionDeleted`   | When a reaction is removed from a comment.                                                                   |
| `subscribed`        | When a user subscribes to a comment annotation using the option in the UI.                                   |
| `unsubscribed`      | When a user unsubscribes from a comment annotation using the option in the UI.                               |

## Webhook Data

| Field                | Type              | Required | Description                                                                                                                                                                                                          |
| -------------------- | ----------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `webhookId`          | string            | Yes      | The unique identifier for the webhook event.                                                                                                                                                                         |
| `commentAnnotation`  | CommentAnnotation | Yes      | The target CommentAnnotation object on which the event happened.                                                                                                                                                     |
| `targetComment`      | Comment           | Optional | The target Comment object on which the event happened. This field will not be present if the event was at CommentAnnotation level. Eg: deleted the entire comment annotation, resolved comment, approved comment.    |
| `actionType`         | string            | Yes      | This can have the values listed above                                                                                                                                                                                |
| `notificationSource` | string            | Yes      | Indicates the source of the notification                                                                                                                                                                             |
| `actionUser`         | string            | Yes      | Contains information about the user who performed the action, including their name, email, and user ID.                                                                                                              |
| `metadata`           | string            | Yes      | This field contains additional metadata related to the annotation, such as the API key, client document ID, document ID, and information about various locations where the annotation is associated with a web page. |

<ResponseExample>
  ```js Webhook Data
  {
    "webhookId": "-Nvmw84XtUUHIsrcKAvI",
    "commentAnnotation": {
      "annotationId": "-O7Yi14ES3EPayuzQ54J",
      "annotationIndex": 20,
      "comments": [
        {
          "commentHtml": "@Jim Halpert can you take a look?",
          "commentId": 822004,
          "commentText": "@Jim Halpert can you take a look?",
          "from": {
            "clientOrganizationId": "velt-sample-app",
            "color": "#67DBF4",
            "email": "peppa.pig@velt.dev",
            "initial": "P",
            "isAdmin": false,
            "name": "Peppa Pig",
            "organizationId": "392580a690394bfadd823101f2b05513",
            "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Fpeppa_pig.svg?alt=media&token=a9fc83f7-b347-4868-8d52-0e888f0de73a&_gl=1*jzxghx*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMTQ5LjQyLjAuMA..",
            "textColor": "#fff",
            "type": "signedIn",
            "userId": "user0",
            "userSnippylyId": "195298461116078"
          },
          "lastUpdated": "2024-09-24T11:08:49.724Z",
          "status": "added",
          "taggedUserContacts": [
            {
              "contact": {
                "email": "jim.halpert@dundermifflin.com",
                "initial": "J",
                "name": "Jim Halpert",
                "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Frosy_rabbit.svg?alt=media&token=4e65a9e3-080d-4416-839d-e761b6b37181&_gl=1*156om5t*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMjUzLjYwLjAuMA..",
                "userId": "e54d19af-0e43-4364-819f-0a8b18a280fb",
                "userSnippylyId": "5236622904561187"
              },
              "text": "@Jim Halpert",
              "userId": "e54d19af-0e43-4364-819f-0a8b18a280fb"
            }
          ],
          "to": [
            {
              "email": "jim.halpert@dundermifflin.com",
              "initial": "J",
              "name": "Jim Halpert",
              "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Frosy_rabbit.svg?alt=media&token=4e65a9e3-080d-4416-839d-e761b6b37181&_gl=1*156om5t*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMjUzLjYwLjAuMA..",
              "userId": "e54d19af-0e43-4364-819f-0a8b18a280fb",
              "userSnippylyId": "5236622904561187"
            }
          ],
          "type": "text"
        },
        {
          "commentHtml": "test",
          "commentId": 719893,
          "commentText": "test",
          "from": {
            "clientOrganizationId": "velt-sample-app",
            "color": "#2c83fc",
            "email": "freddy.froglet@velt.dev",
            "initial": "F",
            "isAdmin": false,
            "name": "Freddy Froglet",
            "organizationId": "392580a690394bfadd823101f2b05513",
            "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Ffreddy_froglet.svg?alt=media&token=e3b2e292-6480-4507-9da3-21a62a1346d4&_gl=1*s4yycs*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMDQzLjcuMC4w",
            "textColor": "#fff",
            "type": "signedIn",
            "userId": "user8",
            "userSnippylyId": "4291391246842733"
          },
          "lastUpdated": "2024-09-24T11:11:58.344Z",
          "status": "added",
          "type": "text"
        }
      ],
      "from": {
        "clientOrganizationId": "velt-sample-app",
        "color": "#67DBF4",
        "email": "peppa.pig@velt.dev",
        "initial": "P",
        "isAdmin": false,
        "name": "Peppa Pig",
        "organizationId": "392580a690394bfadd823101f2b05513",
        "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Fpeppa_pig.svg?alt=media&token=a9fc83f7-b347-4868-8d52-0e888f0de73a&_gl=1*jzxghx*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMTQ5LjQyLjAuMA..",
        "textColor": "#fff",
        "type": "signedIn",
        "userId": "user0",
        "userSnippylyId": "195298461116078"
      },
      "lastUpdated": 1727176311596,
      "pageInfo": {
        "baseUrl": "https://velt-vercel-style-toolbar-demo.vercel.app",
        "commentUrl": "https://velt-vercel-style-toolbar-demo.vercel.app/?scommentId=-O7Yi14ES3EPayuzQ54J",
        "deviceInfo": {
          "browserName": "Chrome",
          "browserVersion": "128",
          "deviceType": "Mobile",
          "orientation": "landscape",
          "osName": "Macintosh",
          "osVersion": "10.15.7",
          "screenHeight": 900,
          "screenWidth": 1440,
          "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
        },
        "path": "/",
        "screenWidth": 804,
        "title": "Web App | Velt Demo",
        "url": "https://velt-vercel-style-toolbar-demo.vercel.app/"
      },
      "status": {
        "color": "#625DF5",
        "id": "OPEN",
        "lightColor": "#E7E8FA",
        "name": "Open",
        "svg": "\n      <svg\n        width=\"16\"\n        height=\"16\"\n        viewBox=\"0 0 16 16\"\n        fill=\"none\"\n        xmlns=\"http://www.w3.org/2000/svg\"\n      >\n        <path\n          fill-rule=\"evenodd\"\n          clip-rule=\"evenodd\"\n          d=\"M8.00016 13.3333C10.9457 13.3333 13.3335 10.9455 13.3335 8.00001C13.3335 5.05449 10.9457 2.66668 8.00016 2.66668C5.05464 2.66668 2.66683 5.05449 2.66683 8.00001C2.66683 10.9455 5.05464 13.3333 8.00016 13.3333ZM8.00016 14.6667C11.6821 14.6667 14.6668 11.6819 14.6668 8.00001C14.6668 4.31811 11.6821 1.33334 8.00016 1.33334C4.31826 1.33334 1.3335 4.31811 1.3335 8.00001C1.3335 11.6819 4.31826 14.6667 8.00016 14.6667Z\"\n          fill=\"currentColor\"\n        />\n      </svg>\n      ",
        "type": "default"
      },
      "subscribedUsers": {
        "3604c43f40557d7aa27ff4d0f72202a3": {
          "type": "auto",
          "user": {
            "email": "jim.halpert@dundermifflin.com",
            "initial": "J",
            "name": "Jim Halpert",
            "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Frosy_rabbit.svg?alt=media&token=4e65a9e3-080d-4416-839d-e761b6b37181&_gl=1*156om5t*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMjUzLjYwLjAuMA..",
            "userId": "e54d19af-0e43-4364-819f-0a8b18a280fb",
            "userSnippylyId": "5236622904561187"
          }
        },
        "3d517fe6ebab7b8cfcf98db6259c8a59": {
          "type": "auto",
          "user": {
            "clientOrganizationId": "velt-sample-app",
            "color": "#67DBF4",
            "email": "peppa.pig@velt.dev",
            "initial": "P",
            "isAdmin": false,
            "name": "Peppa Pig",
            "organizationId": "392580a690394bfadd823101f2b05513",
            "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Fpeppa_pig.svg?alt=media&token=a9fc83f7-b347-4868-8d52-0e888f0de73a&_gl=1*jzxghx*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMTQ5LjQyLjAuMA..",
            "textColor": "#fff",
            "type": "signedIn",
            "userId": "user0",
            "userSnippylyId": "195298461116078"
          }
        },
        "7668f673d5669995175ef91b5d171945": {
          "type": "manual",
          "user": {
            "clientOrganizationId": "velt-sample-app",
            "color": "#2c83fc",
            "email": "freddy.froglet@velt.dev",
            "initial": "F",
            "isAdmin": false,
            "name": "Freddy Froglet",
            "organizationId": "392580a690394bfadd823101f2b05513",
            "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Ffreddy_froglet.svg?alt=media&token=e3b2e292-6480-4507-9da3-21a62a1346d4&_gl=1*s4yycs*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMDQzLjcuMC4w",
            "textColor": "#fff",
            "type": "signedIn",
            "userId": "user8",
            "userSnippylyId": "4291391246842733"
          }
        }
      },
      "type": "comment"
    },
    "targetComment": {
      "commentHtml": "test",
      "commentId": 719893,
      "commentText": "test",
      "from": {
        "clientOrganizationId": "velt-sample-app",
        "color": "#2c83fc",
        "email": "freddy.froglet@velt.dev",
        "initial": "F",
        "isAdmin": false,
        "name": "Freddy Froglet",
        "organizationId": "392580a690394bfadd823101f2b05513",
        "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Ffreddy_froglet.svg?alt=media&token=e3b2e292-6480-4507-9da3-21a62a1346d4&_gl=1*s4yycs*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMDQzLjcuMC4w",
        "textColor": "#fff",
        "type": "signedIn",
        "userId": "user8",
        "userSnippylyId": "4291391246842733"
      },
      "lastUpdated": "2024-09-24T11:11:58.344Z",
      "status": "added",
      "type": "text"
    },
    "actionType": "added",
    "notificationSource": "comment",
    "actionUser": {
      "clientOrganizationId": "velt-sample-app",
      "color": "#2c83fc",
      "email": "freddy.froglet@velt.dev",
      "initial": "F",
      "isAdmin": false,
      "name": "Freddy Froglet",
      "organizationId": "392580a690394bfadd823101f2b05513",
      "photoUrl": "https://firebasestorage.googleapis.com/v0/b/snippyly-sdk-external/o/avatars%2Ffreddy_froglet.svg?alt=media&token=e3b2e292-6480-4507-9da3-21a62a1346d4&_gl=1*s4yycs*_ga*NTc3MjEzMjIwLjE2NjEwODkwMDU.*_ga_CW55HF8NVT*MTY5NzE0MTIzNC4zMzMuMS4xNjk3MTQyMDQzLjcuMC4w",
      "textColor": "#fff",
      "type": "signedIn",
      "userId": "user8",
      "userSnippylyId": "4291391246842733"
    },
    "metadata": {
      "apiKey": "AN5s6iaYIuLLXul0X4zf",
      "clientDocumentId": "toolbar",
      "clientOrganizationId": "velt-sample-app",
      "documentId": "8069511984882017",
      "documentName": "toolbar",
      "organizationId": "392580a690394bfadd823101f2b05513",
      "pageInfo": {
        "baseUrl": "https://velt-vercel-style-toolbar-demo.vercel.app",
        "path": "/",
        "title": "Web App | Velt Demo",
        "url": "https://velt-vercel-style-toolbar-demo.vercel.app/"
      }
    },
    "platform": "sdk"
  }
  ```
</ResponseExample>


# Huddle Webhooks



The `Huddle` component will emit webhook notifications when a user creates or joins a group huddle.

To read more about how to setup webhooks with our SDK, [click here](https://docs.velt.dev/webhooks/overview).

## List of Action Types

| Action Type | Description                      |
| ----------- | -------------------------------- |
| `created`   | When a `User` created a `Huddle` |
| `join`      | When a `User` joins a `Huddle`   |

## Webhook data

| Field                | Type       | Required | Description                                  |
| -------------------- | ---------- | -------- | -------------------------------------------- |
| `webhookId`          | string     | Yes      | The unique identifier for the webhook event. |
| `actionType`         | string     | Yes      | Type of action: created or joined            |
| `notificationSource` | string     | Yes      | Source of notification: huddle               |
| `actionUser`         | UserObject | Yes      | The user who performed the action            |
| `metadata`           | object     | Yes      | Metadata related to the action               |

<RequestExample>
  ```jsx Huddle Created
  {
    "webhookId": "-Nvmw84XtUUHIsrcKAvI",
    "actionType": "created",
    "notificationSource": "huddle",
    "actionUser": {
      "clientOrganizationId": "7e2aed5bc102d06f740ab92afdf58e78f9d34d409555d19a35389309c80f4b4f",
      "color": "#19bcfe",
      "email": "john@trysnippyly.com",
      "organizationId": "7e2aed5bc102d06f740ab92afdf58e78f9d34d409555d19a35389309c80f4b4f",
      "name": "John Smith",
      "plan": "free",
      "type": "signedIn",
      "userId": "1",
    },
    "metadata": {
      "apiKey": "Emcfab4ysRXaC1CZ8hmG",
      "clientDocumentId": "12-4-24",
      "documentId": "1856907974154638",
      "locations": {
        "5638605251172150": {
          "location": {
            "id": "location1",
            "locationName": "Location 1"
          },
          "locationId": 5638605251172150,
          "pageInfo": {
            "baseUrl": "http://localhost:3000",
            "path": "/",
            "title": "Velt React Demo",
            "url": "http://localhost:3000/"
          }
        }
      },
      "pageInfo": {
        "baseUrl": "http://localhost:3000",
        "path": "/",
        "title": "Velt React Demo",
        "url": "http://localhost:3000/"
      }
    },
    "platform": "sdk"
  }
  ```

  ```jsx Huddle Joined
  {
    "webhookId": "-Nvmw84XtUUHIsrcKAvI",
    "actionType": "joined",
    "notificationSource": "huddle",
    "actionUser": {
      "clientOrganizationId": "7e2aed5bc102d06f740ab92afdf58e78f9d34d409555d19a35389309c80f4b4f",
      "color": "#ff7162",
      "contacts": [
        {
          "email": "john@trysnippyly.com",
          "name": "John Smith",
          "userId": "1"
        },
        {
          "email": "sarah@trysnippyly.com",
          "name": "Sarah Wilson",
          "userId": "3"
        }
      ],
      "email": "maria@trysnippyly.com",
      "organizationId": "7e2aed5bc102d06f740ab92afdf58e78f9d34d409555d19a35389309c80f4b4f",
      "name": "Maria Garcia",
      "plan": "paid",
      "type": "signedIn",
      "userId": "2",
    },
    "metadata": {
      "apiKey": "Emcfab4ysRXaC1CZ8hmG",
      "clientDocumentId": "12-4-24",
      "documentId": "1856907974154638",
      "pageInfo": {
        "baseUrl": "http://localhost:3000",
        "path": "/",
        "title": "Velt React Demo",
        "url": "http://localhost:3000/"
      }
    },
    "platform": "sdk"
  }
  ```
</RequestExample>


# Overview



Set up a webhook endpoint to receive real-time notifications for the following Velt events:

*   [Comments](/webhooks/comments-webhooks)
*   [Huddle](/webhooks/huddle-webhooks)

## Setting up a Webhook

To enable Webhooks go to the Configurations -> Webhook Service in the Velt Console, or [click here](https://console.velt.dev/dashboard/config/webhook)

### **Webhook Auth Token**

*   Optional security feature to authenticate webhook requests.
*   Set a unique auth token in your Velt console's webhook settings.
*   We add this token to the Authorization header of each request as `Basic YOUR_AUTH_TOKEN`.
*   Helps you verify that requests are from Velt, not from unauthorized sources.

### **Endpoint URL**

*   This is the endpoint that we will send the webhook data to. This is usually hosted on your server.

### **Payload Encoding**

*   Enable Base64 encoding for webhook payloads (disabled by default).
*   Addresses issues with payloads containing HTML tags that may fail due to strict endpoint policies.
*   If enabled, ensure your server can decode Base64 encoded payloads.
*   Example of decoding a Base64 encoded payload:

    ```js
    const encodedData = "eyJ0ZXN0IjoxLCJ0ZXN0MSI6IjxkaXY+PC9kaXY+In0="
    const decodedData = Buffer.from(encodedData, 'base64').toString('utf-8');
    console.log(JSON.parse(decodedData));
    ```

### **Payload Encryption**

*   Enable payload encryption for enhanced security (disabled by default).
*   Configure this option in the [Velt Console](https://console.velt.dev/dashboard/config/webhook).
*   Encryption details:
    *   Payload encryption: AES-256-CBC
    *   Key encryption: RSA with PKCS1 OAEP padding and SHA-256 hash
*   Public key format:
    *   Provide only the base64-encoded key string, without PEM headers/footers
    *   Recommended key size: 2048 bits
*   Example of setting up decryption for Node.js:

<Tabs>
  <Tab title="Sample Encrypted Payload">
    ```js
    {
      "encryptedData": "1rtsa9UVvXzkP+u0ax2TOlz6xKcwKXhmtHyQF1I4II8X4n9uYb944Q/6AfUNFc2zQj9+AWJIV1Gtoo0j+j5VI8qS4kCVnP4In6v0I3wVECldgZsNAwwD4wKp85OJZUJL4scQmJJK+XXmMNGOW094BcIIa6zKRqYKja5RBm5zEj3k1qsP3WZkUXpggJ4FNuHkWX2nkoDLP5Rby6CY186TEeBIxY+aKS6FyWmOiDDC6ZfuY++BFNJbksNvsbBogDqHB2qa30nK9oEcOKSsXdU4AYof/mPOG01fK2diK3vyk4qcL83mJ0cXm7+SbM+FBFeJpdR+A7iIez1XrdnGlAqppnSfDoNBv2WZ/lRyZJWOyW7QHySMNTn746+JDr8oltIBDVUx5c2m8A/YeQ6E3wWEjjRZcfz3GNSzpEx+jqeNxS0StN7BUXUyHt3786EaXiUtjb2OtrP56mlidXytdHhPZPOy7stRwHnwgXfm5aLsS2yJSs3gSSUubL+ka4fhaJsqxtgXQATSh0RtNXSmAbx930DKn2DipbP23fJRduju/GP1nHnKuy8bOuyB5Du//RrysvKVC4+lMd4mVIc7cSXe25qcPjJFZGpJtJdkNwOZoWCmxMSdR32HBgo7KWJeOWqnWyuLdjQOaxol+JtTu8lopeQk7qfncEXMLcT7YRVQ4t1LZ5T9o4pZEtaOg1LwyX58VQS1OHvgBFWlEPxLfdS1r4c1YzMXLNA4sfYEp06Z11IlEFVCtWobK5//tLc+sIpwfMzdJ3VtVl9Z2XB9kASlnHf88eOdtzvn5A0CRhVBY/v855CttAy/WlPINtXxXSxm9oVMjrBFueWAZ3LQiXDl25to62L5i0NR93zEBKj1BG8egy3F27o8s5kcvrwpc3NGrmDe7x3S11noDAFsxZRWpHnRIapHcsrLWOjWVEumvUxlApKGKL3Ax80XBoN+aTNG4SXGq3dRHSneIs/MNSb0BGWoOD5U5ow58R1tvpzJHtLLnmesL1Vhr23Cug8KHU2q7+e8AnGGPTJIRKfVXjocMDclhDAk5/nuvtUTYG/hRZEQ1yCx3T7H08I6GvyOv4ErtKr+r883hXSYzf1K9eqk7de5mnmxwSEiAh0zagvZ+lMYhWpayeo+xHvtoyzfTsLNyXKc6AYZxfoIVK6UuBfkDnXiAh+NuJDa3wKwig13gQX8GmdJXeSSatI6uuXI1IU5xKIXysaHeAOaHfni+cfDgvUZTtVbWc1qDcNOVEUSl9KsjOUUgdzvST1tJ1ezMNZFbhlrPB3t5y0XvM9QQh1GyyeABxHl8nH/Icrp2Shf5vBntNbRZ3PlzK7nVtgTxXaKhZnGobwY7uruPpahNfkEi83JvOOnHeHBMXrVMAr8GHDRi8099wzvJRHYcb2p6eWocQsDV1X6tcTLuxj3EHGwykWREkkTDQ5C/F40n97PP0U2cxSGJIMePUwgAYw5OFo0dJMsU1HvXjm+2JoO8DkdwPl3Bc9F22trvsA3QecUCKQDGMTuFrFxtlubtJYtVl7w3pBST0SCKx3G2QiycRz0FMWv2FJpazQl6jE4xEqeKf7fiUn/QIo4Levk745LPhfr2tzlXbkdZ2q9TtmSAs5hjpK7ndswbIbvV8Ju5V8mDJXSR0y0NKG2C/8/vTB0xfqYtW/Bv3cXj6do9UQzP6fOFC4SGvYh/l8yohJmCTFq0tETqvZr9Atw9ZOz2cIBFx76wlS/eR9iB/JZ3DGM+2THC6Mjv70ipWX32UW7620Bb5KONm3Vw0eeIHckUn6QaHGfFL/URT6mr7YCJhG5lZynWYZcLv/ffWuFcSmO9p0xCrwqqPEjdaaGs52mqmA4Ikt9MulKAEp6p65V1vxt7Tdy6m9UVjzbEy1zFuU9iOHBAAaj6A8Mj1EEUe6sNx3fLHnC2c0+2Zf3eUxMZPm5dQZPOUXLI28yoCliBIhTYTSh7ATULDDvcnNMs/ziuG7WT/U1wuIHkT5kEE73tnG1EZY4RDODbQobmpBegcuUEh64HEGS7+aK/KPYWxFxWW5oVd0Dc7kvpariXqEhlNdDY65b2T8uBw8bI/HrfvT8d0EnsPz26B1xKZYqyusWnlR+10KdYzPNoupx8vWk74PW8zI5qlcV497SPtvn12a3wvZ8adJzMuP4hsBoKHG/M2nf0lOMbo1gcbHbT0FqcHE3mixY3lU+UnNC5jpmNCs1tK8yqeQdVtHE3YM4Y5SsnBTJddUWVpUxZ6rlU+H2NW/uGcDLBs3HmERTn1l6E1mmqKB2kPA/+Y/YbILXNojbkgRE/3lki5kX4+pjHDxF/mWEEeXpjIl4yKG97mVS2J0dGoJ5CqLv6/CdHhtwu35UydBVDVGHywufVLwPgEiDA9RklM/bQw3ojdlTrn6+irDcz8/Tj7KmK2votLaN6yIEM8Ex2htyBlyX/47eEsh63nSNwSx+uPcTxjH9N5cJpWzJ2KcBMIqZsWOTgISBUndgRdoVTFySY2XwbHlDjh8RCLLBsYRhvOK+nvNqEBnrfzz81B/sqDO1whQDTKT3ZcFnZouaVImRGHcOt0sRioq/JGHAHzRjyc/V9Gb/zTlI8QQob5y5k7dfReAy1rGdkeIa3LXSwWGz8hDjEnGsGGIC4evdiefgoJHkhzEywi/QUEOOnqms/0BzexbLP+89qMgGMlEbA9iLAW/BZgsAkxm+NHqGNtz9HDJStpqewElgjMQ+wV3TUGbrmY0O/FyQn/CXyhXjdRC0/5S1tZnzBMyolHF2a5L5EAzGck2MuV7TgLs6LcvGm7kIeq0vmBCkiUB4IBHMhraU7Ba+cC+CW7tDK0Tkanri5KSMXSXamJpU869Jcsk1JLm69ATMl3eIb5rPx5+GbPUrRogEUP3HQeLMQP8jjq6fVwzGPQByF70t0fE+Z23NuCLzhVss0YkMmzcKK8GjKCJ0vnCA0qanxovpDgCOHjgxvy44N+QNWfUynIKVHS9m7FDE3RgKf7rOfSM9vJ7F/KWo7kywi36ajuFbWcON/MTvlpPUhGm5dboiz3vyfpTWkQbd9XX7SPVBWCkvGg+A87R7RSN8bsWbmYm5m2wt3jrkBVSDn5FV3rek6X0GSpTDTWJ9ktmjKtshplXn7fx7XAKtS4hpEMGhZwi/LWvfTsGqOJlqi2FwYPLI7SVunch2VSfssejrfwxJHPqF50wTv6ax28lp7wToqsVunZprdhyY++gds/LAz083dZLM3EYcbHuGVXiNRFxptpiQNjEnyjZX0fc8UF1W2icDt7Gd5Pp2ckaPERLE+tJ+ackMxomH2/HjFB3XRXlDCoKuljtJ2cbw/gVPmHtV7Qw2w6tWaCzYP3g1D47BlrIqBV4RWjcPRjthfcWPnwUSSHwlJ4dLMQ+cJ402ol+HUukAKpkh5lcjME0uaD8KKReD/Ee9r4kubIR7z9JViXjnJJl3Jxr6KtK3abrg8cG8qVFRr5NDhxbfs9NY/zGDvbgt0GMWXRTi4oMrSkDKthZSWjVezDzPk11AMQ1E+SJSoSXgwUl1rbWPg0O29prkQdfdKQmZcaO5oj7+f3kSPsIOE9+Qn43VOxOWWybkCzSvEbzLgmuov5C8EWYeJgh13qDcNSwNdt4PgAqIq+tikKNUo9qeM9/q20an+i20fatPAcvrRes+xxnIBXmlPDCj02THjX4EulV2KE+nNxFnCrNvFKYp2bEAegJ2neqfeefDDDhn+t7OK9/73v3O3qnEwSyBlt+pEyHfLjv3Cm7Ik7JA5NUQ/nsS3JdC8OYy2i1DWSvi1qsP3ixAVCR7qBVdoOF2Lv5y2GWrJ0EvVcGqaPBnUezMGMdozNjreschNJvRlp3D72dGGQgs00GHyHbIQ5wicC5p+PiZ2z1EUBN7DiDy9ShQPKEDJtISiSrSaPkDPKpW7SxmSfDaLOIxEy4daAupV0gj7yTtrkpEvJjRECpa0kuKFP3/eFVVp/nIjWDzFASfDvYiry90dDrvLxO3tosuvMVfhXcOy/zbyeCkObaFgc3OkO4z2r4X4Vwt18BoRAammiEfgCbnhywl/CmLrSwV1qSjUgALh/XUPkqXCkqerNjYTlZw5NdRUKmheUXHYGwo4Z+xPfDtiHk1N5vRgNL9/qXsgt813spju9kDMGQGiXlrOgIyhArHR5p2B4S3FjRQ/lEoP5+5wN+9tBKYrR79sZXNS8CwR0BPrOoY9GQCYFdxrBtyH6KOWg29FVXNodt2Yvot7ktofcen1zwQJOAr0KTyqF9/TIltO+hS7swSzZMjV368SEPYjrtXfnXNWYltOS2zJAWYeqr0XLrL+iHbbOQLC7Rk0mnizmUt9wdefz4MtfXZNcdKR4LPsOqYyIz5ux90XiCbvcNZJaRa2/dzecv/koLQPbKzFPGxKiUOsHAa5SEGgbWFZE4Y9CBFS4nCuEOgUnVz9XtFAEP4dazc2cxjYLVzaG5msOiOY1O5ZygYMeVZfdKaITg7gMPbkL3Lpzo7QBMXcHmT5YAUeNaSbHxvgg45Jn8r7W72EQP9tF7SPKiPvxo91xkB7MA3JOcZXC1qymTUWqjO038wSShK48kE+qgu7V9rjP5fOCDW3+3338eifxqS7Zq6FSO053c5W2c8wFR4iw==",
      "encryptedKey": "OzSHFXzrXFC5wDvM5NPRkriY/NaC/USvFUPE+f4NZ30tiD2qb8sJM2XT2K7uNIZ05uDLfsJ6/BbEoYC1SOPXcFJMYqRiYFiI9RWrNgR4EtPWZ84RgrmxGcZZjzSqHzjuls8g++cuqJGRV+ePbTRH+z2OuZZu0vMKZiemaZpHL46Ewi9HUnbRDXvOlKFFHmQm5tayZ7m7Mv5iu4T5R3DPEAHlZnGqtP98ToLxUJUS2Eku/iLHXRmhmZXn55Qt5GYiyss8P5/miPqJCu1QG0CStn5Nsl4KvU+I4QYAOcMFWWUAGofOwPWtt8vPh8Bx+7t7BbayKpA4ZUEWWAjC+zASxg==",
      "iv": "SHM0UHU5WXoyTG03TnExWA=="
    }
    ```
  </Tab>

  <Tab title="Sample Decryption Code">
    ```javascript
        const crypto = require('crypto');

        /**
         * Decrypts the symmetric key using the provided private key.
         * @param {string} encryptedKey - Base64 encoded encrypted symmetric key
         * @param {string} privateKey - RSA private key
         * @returns {Buffer} Decrypted symmetric key
         */
        function decryptSymmetricKey(encryptedKey, privateKey) {
            try {
                const encryptedSymmetricKey = Buffer.from(encryptedKey, 'base64');
                const decryptedSymmetricKey = crypto.privateDecrypt(
                    {
                        key: `-----BEGIN RSA PRIVATE KEY-----\n${privateKey}\n-----END RSA PRIVATE KEY-----`,
                        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
                        oaepHash: 'sha256',
                    },
                    encryptedSymmetricKey
                );
                return decryptedSymmetricKey;
            } catch (error) {
                console.error('Error decrypting symmetric key:', error);
                throw new Error('Failed to decrypt symmetric key');
            }
        }

        /**
         * Decrypts the webhook data using the provided symmetric key and IV.
         * @param {string} encryptedWebhookData - Base64 encoded encrypted webhook data
         * @param {Buffer} symmetricKey - Decrypted symmetric key
         * @param {string} payloadIv - Base64 encoded initialization vector
         * @returns {Object} Decrypted webhook data as a JSON object
         */
        function decryptWebhookData(encryptedWebhookData, symmetricKey, payloadIv) {
            try {
                const iv = Buffer.from(payloadIv, 'base64');
                const decipher = crypto.createDecipheriv('aes-256-cbc', symmetricKey, iv);
                let decryptedData = decipher.update(encryptedWebhookData, 'base64', 'utf8');
                decryptedData += decipher.final('utf8');
                return JSON.parse(decryptedData);
            } catch (error) {
                console.error('Error decrypting webhook data:', error);
                throw new Error('Failed to decrypt webhook data');
            }
        }

        // Example usage:
        // const decryptedKey = decryptSymmetricKey(encryptedKey, privateKey);
        // const decryptedData = decryptWebhookData(encryptedWebhookData, decryptedKey, payloadIv);
    ```
  </Tab>
</Tabs>