Skip to main content

Libraries

  • @veltdev/react
  • @veltdev/client
  • @veltdev/sdk
5.0.2-beta.8
March 12, 2026

New Features

  • [Recorder]: Added recorder field on VeltDataProvider accepting a RecorderAnnotationDataProvider. When configured via setDataProviders(), recording PII (user identity, transcription, attachment URLs) is stripped from annotations before being written to Velt’s Firestore and routed to your own storage via resolver callbacks or config-based HTTP endpoints. On read, the resolved PII is merged back transparently. Learn more →
// Using API methods
client.setDataProviders({
  recorder: {
    get: async (request) => { /* fetch PII from your backend */ },
    save: async (request) => { /* save PII to your backend */ },
    delete: async (request) => { /* delete PII from your backend */ },
    config: {
      getConfig: { url: 'https://api.yourapp.com/recordings/get' },
      saveConfig: { url: 'https://api.yourapp.com/recordings/save' },
      deleteConfig: { url: 'https://api.yourapp.com/recordings/delete' },
      additionalFields: ['customField1', 'customField2'],
    },
    uploadChunks: false,
    storage: {
      save: async (request) => { /* upload file to your storage */ },
      delete: async (request) => { /* delete file from your storage */ },
    },
  },
});
Use isRecorderResolverUsed on RecorderAnnotation to show a loading state while PII is being fetched, and isUrlAvailable to show an upload progress indicator while the recording URL is still a local blob.
  • [REST API]: Added two endpoints for asynchronous document migration. Migrate Documents initiates a migration that migrates all data from one document to another. Migrate Documents Status → polls progress using the migrationId returned by the initiate call.

Improvements

  • [Recorder]: Added RECORDER_RESOLVER to CoreEventTypesMap with a full 3-stage lifecycle (request formed → triggered → result/error) for get, save, and delete resolver operations. Consistent with the existing comment, reaction, and attachment resolver event patterns.
  • [Core]: The get, save, and delete methods on CommentAnnotationDataProvider, ReactionAnnotationDataProvider, and AttachmentDataProvider are now optional. Developers using config-based URL endpoints (config.getConfig, config.saveConfig, config.deleteConfig) no longer need to supply placeholder callbacks. ResolverConfig also gains a new additionalFields?: string[] property for including custom fields in resolver payloads.
  • [Core]: Added attachmentScope?: string to UploadFileOptions to specify which scoped AttachmentDataProvider to route an upload to (e.g., 'default' for comment attachments, 'recorder' for recording files). Defaults to 'default' when omitted.

Bug Fixes

  • [Comments]: Fixed text selection highlighting not activating for submitted (non-draft) comment annotations. The textClicked flag is now set correctly for all selected annotations when last is true, not only drafts.
  • [REST API]: Fixed “Transaction too big” errors during document migration by reducing Firestore batch size from 500 to 100 in subcollection copy, notification copy, and user doc config operations. Migrations involving documents with large notification or comment payloads will no longer fail.
5.0.2-beta.7
March 10, 2026

New Features

  • [Activity Logs]: A complete, real-time record of everything that happens across your product. Velt automatically generates activity log records for Comments, Reactions, Recorder, and CRDT features, and you can push custom events (deployments, status changes, escalations) into the same timeline using createActivity(). Subscribe org-wide for admin dashboards, filter by document for inline timelines, or scope by feature type to reduce noise. Learn more →
  • [CRDT]: Added setActivityDebounceTime(time) on CrdtElement to control how long editor keystrokes are batched before flushing a single activity log record. Default: 10 minutes. Minimum: 10 seconds. Documentation →
  • [Activity Logs REST API]: Added CRUD endpoints for activity log records (/v2/activities/get, /v2/activities/add, /v2/activities/update, /v2/activities/delete). Also added a triggerActivities flag on POST /v2/commentannotations/add to auto-create activity log records when comments are added. REST API Reference →

Bug Fixes

  • [Comments]: Fixed temp annotation context being cleared prematurely during comment submission in composer mode, preventing stale context from affecting subsequent comment operations.
5.0.2-beta.6
March 9, 2026

Bug Fixes

  • [Comments]: Fixed sidebar filters restored from sessionStorage being overwritten by the initial empty emission on page reload.
  • [Comments]: Fixed DOM annotation visibility diverging from sidebar filter state when filters were restored from session storage or set via defaults.
  • [Comments]: Fixed mergeClientFilters not handling null or empty {} filter objects correctly, which prevented filters from being cleared.
  • [Comments]: Fixed autocomplete hotkey button inserting a duplicate character when the hotkey already existed at the cursor position.
  • [Comments]: Fixed autocomplete cursor save/restore failing inside shadow DOM.
  • [Comments]: Fixed partial @mention replacement when one tagged user’s name is a prefix of another (e.g., @Alice corrupting @AliceSmith).
  • [Comments]: Fixed multi-thread comment annotations not being filtered by sidebar filter state in the DOM.
5.0.2-beta.5
March 2, 2026

New Features

  • [UI Customization]: Added 13 standalone autocomplete primitive components (VeltAutocompleteOption, VeltAutocompleteChip, VeltAutocompleteEmpty, etc.) for building fully custom autocomplete UIs without requiring the full <velt-autocomplete> panel. Learn More →
  • [UI Customization]: Added multiSelect, selectedFirstOrdering, readOnly, inline, and contacts props to the VeltAutocomplete panel component.

Improvements

  • [Access Control]: AccessRequestEvent and SEMEvent now include totalUsers, presenceSnippylyUserIds, and presenceClientUserIds fields for real-time presence context.
  • [Analytics]: COMMENT_ADDED and COMMENT_STATUS_CHANGED events now include commentAnnotationCreatedAt, taggedClientUserIds, and taggedSnippylyUserIds.
  • [Analytics]: New REACTION_ADDED and REACTION_DELETED events fire with annotationId, commentId, reactionId, and commentMode.
  • [Analytics]: Added CRDT_DATA_UPDATED analytics event with deduplication.

Bug Fixes

  • [Core]: Fixed client.setDocuments() triggering duplicate concurrent initializations when called multiple times in rapid succession with identical document IDs and options.
  • [Comments]: Replaced custom VeltCommentDialogVisibilityBannerDropdownContentUserPicker sub-components with the shared autocomplete component.
5.0.2-beta.4
February 24, 2026

New Features

  • [Comments]: Added Private Comments UI. Enable it with visibilityOptions. Users see a persistent banner below the composer with four visibility levels — public, organization-private, restricted-self, and restricted — and an inline user-picker (search, avatar list, multi-select) when restricted is chosen. Visibility can also be changed after submission from the thread options menu.
<VeltComments visibilityOptions={true} />

// Using API methods
const commentElement = client.getCommentElement();
commentElement.enableVisibilityOptions();
commentElement.disableVisibilityOptions();
The banner surface is fully wireframe-customizable via the new VeltCommentDialogWireframe.VisibilityBanner.* / velt-comment-dialog-visibility-banner-* family.
  • [Comments]: Added AddCommentRequest.visibility field of type CommentVisibilityConfig to set comment visibility at creation time. Previously visibility could only be set after creation via updateVisibility().
const commentElement = client.getCommentElement();
commentElement.addComment({
  annotationId: 'annotation-id',
  comment: { text: 'Visible only to selected users' },
  visibility: {
    type: 'restricted',
    userIds: ['user1', 'user2'],
  },
});

Improvements

  • [Comments]: VisibilityOptionClickedEvent now includes an optional users field containing the list of selected users when visibility === 'restricted'. Previously, the event only reported the visibility type string.
const eventData = useCommentEventCallback('visibilityOptionClicked');
useEffect(() => {
  if (eventData) {
    console.log(eventData.visibility); // 'public' | 'organization-private' | 'restricted-self' | 'restricted'
    console.log(eventData.users);      // populated when visibility === 'restricted'
  }
}, [eventData]);
  • [Comments]: CommentSaveTriggeredEvent now includes a commentAnnotation field with the full annotation object at save time. Handlers for onCommentSaveTriggered can now access comment content, assignment, and visibility state without a separate lookup.
5.0.2-beta.3
February 24, 2026

New Features

  • [Comments]: Added AnonymousUserDataProvider to resolve email → userId mappings for users who are tagged by email in comments but are not part of the contact list. When a comment is saved and a tagged contact or to recipient has an email but no userId, the SDK calls the registered provider to look up the userId and backfills it into the comment data before persisting.
// Option 1: standalone method
client.setAnonymousUserDataProvider({
  resolveUserIdsByEmail: async (request) => {
    // request.emails: string[]
    const map = await yourBackend.lookupUserIds(request.emails);
    return { statusCode: 200, success: true, data: map };
  },
  config: {
    resolveTimeout: 5000,
    getRetryConfig: { retryCount: 2, retryDelay: 300 },
  },
});

// Option 2: via setDataProviders
client.setDataProviders({
  anonymousUser: {
    resolveUserIdsByEmail: async (request) => { /* ... */ },
  },
});
Results are cached in memory for the session; emails already resolved are not re-fetched. On timeout or error, the provider returns whatever was cached and proceeds without the unresolved user IDs. If no UserDataProvider is configured, resolved user IDs are automatically backfilled to the organization database as stub user records ({ userId, name: email, email }). If a UserDataProvider is already configured, the org DB backfill is skipped.

Improvements

  • [Comments]: Comment annotations now store a top-level visibilityConfig field ({ type, organizationId, userIds }) alongside the existing context.accessFields tokens. This makes the original visibility setting inspectable without reversing hashed tokens. Annotations without an explicit visibility setting default to { type: 'public' }. The context.accessFields tokens continue to govern actual access control.
  • [Comments]: When setting restricted visibility, the current user’s userId is now automatically appended to userIds (deduplicated) if not already present. Existing explicit userIds lists are preserved. This applies across enablePrivateMode, addCommentAnnotation, and updateVisibility.
5.0.2-beta.2
February 24, 2026

New Features

  • [Comments]: Added a commentSaveTriggered event that fires immediately when a user clicks the save button, before the async save completes. Use it for immediate pre-save feedback alongside the existing commentSaved event, which continues to fire after the save finishes.
// Using hook
const event = useCommentEventCallback('commentSaveTriggered');

useEffect(() => {
  if (event) {
    console.log('Save triggered for annotation:', event.annotationId);
  }
}, [event]);
The exported CommentSaveTriggeredEvent interface has the following shape:
interface CommentSaveTriggeredEvent {
  annotationId: string;
  metadata: VeltEventMetadata;
}

Improvements

  • [Comments]: The sidebar now automatically returns to the full comment list when all annotations are deselected while in focused thread mode.
  • [Comments]: Page scroll position is now preserved when navigating to a highlighted annotation from the sidebar.
5.0.2-beta.1
February 20, 2026

New Features

  • [Comments]: Added a visibility dropdown to the comment composer, letting users set a comment’s visibility to public or private before submitting. Disabled by default; enable it via the visibilityOptionDropdown prop or API methods. A visibilityOptionClicked event fires on each selection, emitting the annotation ID, full CommentAnnotation, and chosen visibility.
// Declarative prop
<VeltComments visibilityOptionDropdown={true} />

// Using API methods
const commentElement = client.getCommentElement();
commentElement.enableVisibilityOptionDropdown();
commentElement.disableVisibilityOptionDropdown();

// Listening to the event
import { useCommentEventCallback } from '@veltdev/react';
const visibilityEvent = useCommentEventCallback('visibilityOptionClicked');

useEffect(() => {
  if (visibilityEvent) {
    console.log('Visibility selected:', visibilityEvent.visibility);
    console.log('Annotation ID:', visibilityEvent.annotationId);
  }
}, [visibilityEvent]);
To customize the dropdown via wireframes, you can refer to the wireframe documentation.

Bug Fixes

  • [Comments Sidebar]: Fixed the “(This page)” indicator not appearing for locations identified by locationName instead of id. The sidebar now matches the current location by id, locationName, or legacy locationId, in that order.
5.0.1
February 18, 2026

Bug Fixes

  • [Comments]: Fixed temporary composer annotations (prefixed TEMP_COMPOSER_) being inadvertently persisted to the database. Guards were added so temp annotations remain client-only and are never written to the database.
  • [Comments]: Fixed the comment dialog calling markAsRead() for TEMP_COMPOSER_ annotations that do not yet exist in the database. The call is now guarded so only persisted annotations are marked read when a pin is selected.
  • [Comments Sidebar]: Fixed the sidebar failing to identify the current page’s annotation group when a location is configured with locationName but no id. The sidebar now resolves the current location using location.id first, then location.locationName, then alphabetical order.
  • [Notifications]: Fixed a race condition where a stale async call completing after a newer one could overwrite the user’s saved notification config with defaults.
  • [Comments]: Fixed comment pins being placed at incorrect positions on video timelines whose total duration is not a whole number of seconds. Fractional-second durations are now preserved correctly.
5.0.1-beta.4
February 18, 2026

New Features

  • [Comments]: Added enablePrivateMode(config) and disablePrivateMode() methods to set a global visibility policy for all newly created comments. Supports restricted (user-list), organizationPrivate, and public visibility types via the new PrivateModeConfig type.
// Using API methods
const commentElement = client.getCommentElement();

// Restrict all new comments to specific users
commentElement.enablePrivateMode({ type: 'restricted', userIds: ['user-1', 'user-2'] });

// Restrict all new comments to the current organization
commentElement.enablePrivateMode({ type: 'organizationPrivate' });

// Revert to default public visibility
commentElement.disablePrivateMode();
  • [Comments]: Added a commentSaved event that fires after a comment is persisted to the database, providing a reliable signal for triggering downstream actions. The payload includes the annotation ID, full CommentAnnotation, and VeltEventMetadata.
// Using Hooks
import { useCommentEventCallback } from '@veltdev/react';
import { useEffect } from 'react';

const commentSavedData = useCommentEventCallback('commentSaved');

useEffect(() => {
  if (commentSavedData) {
    console.log('Comment saved:', commentSavedData.annotationId);
    console.log('Annotation:', commentSavedData.commentAnnotation);
  }
}, [commentSavedData]);

// Using API methods
const commentElement = client.getCommentElement();
commentElement.on('commentSaved').subscribe((event) => {
  console.log('Comment saved:', event.annotationId);
  console.log('Annotation:', event.commentAnnotation);
});
  • [Notifications]: Added opt-in notification delay and batching pipeline for comment notifications. Configure delayConfig to hold notifications and suppress delivery if a user views the comment during the delay window. Configure batchConfig to accumulate notifications per document or per user before delivery, reducing noise on high-activity content. Webhooks and workflow triggers always fire immediately and are never subject to delay or batching.
{
  "delayConfig": {
    "isEnabled": true,
    "delaySeconds": 30
  },
  "batchConfig": {
    "document": {
      "isEnabled": true,
      "batchWindowSeconds": 300,
      "maxActivities": 10
    },
    "user": {
      "isEnabled": true,
      "batchWindowSeconds": 300,
      "maxActivities": 10
    }
  }
}
Set notificationServiceConfig in your workspace notification settings in the Velt Console. Learn more
  • [Notifications]: Webhook payloads now include per-user notification preferences for all involved users. Depending on the config level, payloads carry either usersOrganizationNotificationsConfig or usersDocumentNotificationsConfig, enabling downstream consumers to route notifications based on each user’s settings. See UserNotificationsConfig for the type definition. Learn more
{
  "webhookId": "notif-123",
  "usersOrganizationNotificationsConfig": {
    "user-1": { "inbox": "ALL", "email": "MINE" },
    "user-2": { "inbox": "ALL", "email": "MINE" }
  }
}
  • [Notifications]: The getConfig notification API now supports a getOrganizationConfig: true option to retrieve org-level notification config for a user. documentIds is now optional in setConfig — omitting it applies the config at the organization level as the user’s default for all documents. setConfig | getConfig
{
  "data": {
    "organizationId": "org-123",
    "userIds": ["user-1", "user-2"],
    "config": {
      "inbox": "ALL",
      "email": "NONE"
    }
  }
}

Improvements

  • [Comments]: Added auto-resolution of the organization ID from the current org configuration when updateVisibility() or enablePrivateMode() is called with type: 'organizationPrivate' and no organizationId is provided.

Bug Fixes

  • [Comments]: Fixed global dark mode toggling not affecting open comment dialogs. Dialog initialization no longer sets a component-level dark mode override that would block ThemeService propagation.
  • [Comments]: Fixed composer placeholder text not reappearing after a user typed and deleted all text. The contenteditable element is now cleared with innerHTML = '' to ensure the CSS :empty::before placeholder renders correctly.
  • [Comments]: Fixed SVG gradient, clip-path, and filter rendering for duplicate emoji reactions. Each emoji SVG instance now receives unique internal IDs via EmojiService.uniquifySvgIds().
  • [Comments]: Fixed priority dropdown showing an incorrect background color in dark mode when no priority was set.
  • [Comments]: Fixed user migration not updating {{userId}} placeholders in commentText/commentHtml and not remapping views/viewedByUserIds by internal user key. All userId references in comment content and view tracking are now correctly updated during migration.
5.0.1-beta.3
February 16, 2026

Improvements

  • [Comments]: Added backward compatibility so V4 custom wireframes using property names allowAssignment, allowEdit, allowToggleNotification, and allowChangeCommentAccessMode automatically resolve to their v5 equivalents. No changes to your wireframe code are required when upgrading from v4 to v5.
  • [Comments]: Added edit composer wireframe reuse in comment thread cards so it now applies the same velt-comment-dialog-composer-wireframe customization as the reply composer. Previously the edit composer always rendered the default template.

Bug Fixes

  • [Comments]: Fixed custom wireframes for nested comment dialog components — including thread cards, priority/status dropdowns, attachment layouts, reply avatars, and seen dropdowns — silently falling back to the default template instead of rendering correctly. This restores the v4 behavior where parent components extracted nested wireframes via querySelector and passed them to children.
  • [Comments]: Fixed veltDynamicTemplate placement in multiple components so it wraps only the replaceable inner content (e.g., an icon) instead of the entire component structure. Previously the default template always rendered and the wireframe content was never injected.
  • [Comments]: Fixed velt-class conditional styling in custom wireframes not resolving correctly for per-item data such as {commentObj.*}, {attachment.*}, and {file.*}. Added applyConditionalClasses() calls with per-item data contexts across 40+ comment dialog primitive components.
  • [Comments]: Fixed click event handlers being lost when custom wireframes replace default content by moving handlers from inside veltDynamicTemplate blocks to wrapper elements outside the template directive. This restores click functionality for custom wireframes on mark-as-read, dropdown items, options, and priority/status items.
  • [Comments]: Fixed per-dialog state (localUIStateSignal) not being propagated to child primitives and veltDynamicTemplate contexts throughout the entire comment dialog component tree, including through wireframe-replaced sections.
  • [Comments]: Fixed custom wireframes using data bindings like <VeltData field="attachment.name" /> displaying empty content by adding per-item data fields (attachment, commentObj, file, item, etc.) to veltDynamicTemplate context objects.
  • [Comments]: Fixed layout issues caused by styled wrapper elements persisting outside the template when wireframes replaced inner content. Visual styling classes (width, height, padding) are now inside the veltDynamicTemplate default content.
  • [Comments]: Restored CSS class names on the priority dropdown content item components to their v4 names (velt-priority-dropdown-content-item, velt-priority-dropdown-content-item-tick, s-priority-*) so existing CSS overrides continue to work without changes.
  • [Comments]: Fixed mark-as-read not firing when clicking a comment in sidebar focused-thread mode or inline comment section mode. Previously the comment dialog is always in a selected state in these modes, preventing the mark-as-read path from triggering.
  • [Comments]: Fixed the attachment image download button not hiding for anonymous users, disabled states, and expired plans. The button now correctly matches v4 behavior.
  • [Comments]: Fixed attachment loading spinners crashing when config.uiState is not yet initialized (e.g., in standalone usage or during initialization race conditions).
  • [Comments]: Fixed sidebar deselection accidentally re-selecting an annotation that was already removed from the selected annotations map by another code path.
5.0.1-beta.2
February 16, 2026

New Features

  • [Comments]: Added enableAttachmentDownload() / disableAttachmentDownload() API methods and an attachmentDownload prop on <VeltComments> to control whether clicking an attachment triggers a file download. A new attachmentDownloadClicked event fires on every attachment click regardless of the download setting, letting you intercept clicks for custom viewers, analytics, or access control. Download is enabled by default so there is no breaking change.
// Declarative prop
<VeltComments attachmentDownload={false} />

// Using API methods
const commentElement = client.getCommentElement();
commentElement.enableAttachmentDownload();
commentElement.disableAttachmentDownload();

// Listening to the event
const handleAttachmentDownloadClicked = useCommentEventCallback('attachmentDownloadClicked');

useEffect(() => {
  if (handleAttachmentDownloadClicked) {
    console.log('Attachment clicked:', handleAttachmentDownloadClicked.attachment.attachmentId);
    console.log('Annotation ID:', handleAttachmentDownloadClicked.annotationId);
  }
}, [handleAttachmentDownloadClicked]);
The exported AttachmentDownloadClickedEvent interface has the following shape:
interface AttachmentDownloadClickedEvent {
  annotationId: string;
  commentAnnotation: CommentAnnotation;
  attachment: Attachment;
  metadata?: VeltEventMetadata;
}

Improvements

  • [Comments]: The wireframe template for the resolve and unresolve buttons in the assignee banner is now nested inside the button component rather than wrapping it, giving custom wireframes direct access to button state, styling, and event handlers. The affected wireframes are velt-comment-dialog-assignee-banner-resolve-button-wireframe and velt-comment-dialog-assignee-banner-unresolve-button-wireframe.
  • [Comments]: Added CSS classes to comment composer attachment components to reflect loading and edit-mode states: .velt-composer-attachment-container, .velt-composer-attachment--loading, and .velt-composer-attachment--edit-mode.
  • [Comments]: Added .s-comment-dialog-assign-to-menu and .velt-thread-card--assign-to-menu CSS classes to the assign-to menu component for more granular styling control.

Bug Fixes

  • [Comments]: Added 'iframe' to the list of non-nestable elements so that getHostElement() returns the iframe’s parent element instead of attempting to place a comment pin inside the iframe document context.
  • [Comments]: Fixed a regression where navigating back from a focused thread triggered an unintended draft auto-save. A guard now skips auto-save when the focused thread dialog is destroyed via back navigation.
  • [Comments]: Fixed stale selection state in the sidebar after back-navigating from a focused annotation. The annotation is now properly deselected from the internal selection map on exit.
  • [Comments]: Thread card attachment components now use isTemplateEmpty() to detect empty wireframe templates instead of a truthy check, so attachments correctly fall back to default rendering when an empty wireframe is provided.
  • [Comments]: Custom thread card wireframes that do not include an edit composer wireframe now automatically render the default edit composer, so inline comment editing remains functional without requiring wireframe changes.
5.0.1-beta.1
February 13, 2026

New Features

  • [Comments]: Added clearContext option to PageModeComposerConfig to control whether comment context is cleared after page mode composer submission. Set clearContext: false to preserve context data across submissions (defaults to true).
// Using Hooks
const commentElement = useCommentUtils();
commentElement.setContextInPageModeComposer({
  context: { documentId: '123', section: 'intro' },
  targetElementId: 'my-element',
  clearContext: false
});

// Using API methods
const commentElement = client.getCommentElement();
commentElement.setContextInPageModeComposer({
  context: { documentId: '123', section: 'intro' },
  targetElementId: 'my-element',
  clearContext: false
});

Bug Fixes

  • [Comments]: Removed host CSS classes velt-composer-open and velt-composer-input-focused from the Comment Dialog Composer component. If your custom styles targeted these classes, update your selectors accordingly.
  • [Comments]: Fixed wireframe template forwarding in Comment Dialog so custom templates set via dialogTemplate are now correctly applied to all child components.
  • [Comments]: Fixed nested wireframe template extraction in Comment Dialog Threads so custom velt-comment-dialog-thread-card-wireframe and velt-comment-dialog-more-reply-wireframe templates are correctly applied.
  • [Comments]: Fixed Mark as Read/Unread wireframe template structure so custom wireframe templates now provide proper control over the button’s internal elements.
  • [Comments]: Added proper wireframe template wrapper to the parent Mark as Read component with a clickable container that includes accessibility attributes for the toggle action.
  • [Comments]: Fixed comment annotation data resolution in button click handlers so commentAnnotation context data now correctly resolves from the updated component config structure.
5.0.0
February 12, 2026

New Features

  • [CRDT]: Added Add CRDT Data REST API to create new CRDT editor data on the backend. Supports text, map, array, and xml types for use with Multiplayer Editing (Yjs).
  • [CRDT]: Added Update CRDT Data REST API to replace existing CRDT editor data. Generates proper CRDT operations so connected clients pick up the change automatically.

Bug Fixes

  • [Comments]: Fixed edit mode not working in thread card messages. Edit mode now properly propagates to comment messages within thread cards.
5.0.0-beta.17
February 12, 2026

Improvements

  • [Comments]: Updated updateVisibility() with type: 'restricted' to auto-default to the current authenticated user when no userIds are provided. Developers no longer need to manually pass the current user’s ID.
// Using hook
const commentElement = useCommentUtils();

// Before: Had to pass userIds manually
commentElement.updateVisibility({
  annotationId: 'annotation-1',
  visibility: { type: 'restricted', userIds: ['current-user-id'] }
});

// After: userIds auto-defaults to current authenticated user
commentElement.updateVisibility({
  annotationId: 'annotation-1',
  visibility: { type: 'restricted' }
});

// Using API method
const commentElement = client.getCommentElement();
commentElement.updateVisibility({
  annotationId: 'annotation-1',
  visibility: { type: 'restricted' }
});
  • [Comments]: Improved performance of getCommentAnnotationsCount() by automatically batching queries when 2+ documentIds are provided. You can customize the debounce delay with debounceMs parameter (default 5000ms).
// Using hook
const commentElement = useCommentUtils();

// Automatically batches when 2+ documentIds are provided
const counts = commentElement.getCommentAnnotationsCount({
  documentIds: ['doc-1', 'doc-2', 'doc-3']
});

// Optional: customize debounce (default 5000ms)
const countsWithDebounce = commentElement.getCommentAnnotationsCount({
  documentIds: ['doc-1', 'doc-2', 'doc-3'],
  debounceMs: 2000
});

// Using API method
const commentElement = client.getCommentElement();
const counts = commentElement.getCommentAnnotationsCount({
  documentIds: ['doc-1', 'doc-2', 'doc-3']
});
  • [Comments]: Deprecated legacy enablePrivateCommentMode(), disablePrivateCommentMode(), and updateAccess() methods. These are replaced by the visibility API. Existing usage continues to work but IDEs will show deprecation warnings.
5.0.0-beta.16
February 11, 2026

Improvements

  • [Core]: Added ability to control Firestore SDK logs via sessionStorage or environment config. By default, logs are silenced to reduce console noise in production.
  • [Performance]: Added GSAP animation detection to reduce MutationObserver overhead. Pages using GSAP now experience ~20x performance improvement (from ~375ms to ~18ms per callback).

Bug Fixes

  • [Comments]: Fixed cursor position loss on mobile when selecting autocomplete options. The cursor now stays at the correct position after selecting @-mentions.
  • [Comments]: Fixed hotkey insertion in autocomplete tool. Clicking the autocomplete trigger button (e.g. ”@”) now inserts at cursor position on all browsers, preserving mention spans.
  • [Comments]: Fixed autocomplete panel click events bubbling through dropdown. Selecting options no longer accidentally triggers underlying elements on mobile browsers.
  • [Comments]: Disabled format options (bold, italic, etc.) by default. To enable, set enableFormatOptions: true in your comment configuration.
  • [Comments]: Fixed cursor position in bottomsheet mode after selecting mentions. The cursor now appears after the mention span instead of jumping to the beginning.
  • [Comments]: Fixed attachment components not receiving parent UI state. Selected and invalid attachment components now correctly react to parent composer state changes.
5.0.0-beta.15
February 11, 2026

New Features

  • [Comments]: Added rich text formatting toolbar for comment composers. Users can apply bold, italic, underline, and strikethrough formatting to emphasize text.
// Using Hooks
import { VeltComments } from '@veltdev/react';

<VeltComments formatOptions={true} />

// Using API methods
const commentElement = client.getCommentElement();
commentElement.enableFormatOptions();
commentElement.disableFormatOptions();

// Configure individual format types
commentElement.setFormatConfig({
  bold: { enable: true },
  italic: { enable: true },
  underline: { enable: false },
  strikethrough: { enable: false }
});
  • [Comments]: Added clearComposer() method to programmatically reset composer state (text, attachments, recordings, tagged users).
// Using Hooks
const commentElement = useCommentUtils();
commentElement.clearComposer({ targetComposerElementId: 'my-composer-1' });

// Using API methods
const commentElement = client.getCommentElement();
commentElement.clearComposer({ targetComposerElementId: 'my-composer-1' });
  • [Comments]: Added getComposerData() method to retrieve current composer state synchronously without subscribing to events.
// Using Hooks
const commentElement = useCommentUtils();
const data = commentElement.getComposerData({ targetComposerElementId: 'my-composer-1' });

if (data) {
  console.log(data.text);
  console.log(data.annotation);
  console.log(data.targetComposerElementId);
}

// Using API methods
const commentElement = client.getCommentElement();
const data = commentElement.getComposerData({ targetComposerElementId: 'my-composer-1' });
  • [Comments]: Added context prop to VeltCommentDialogComposer to attach custom context data to comments created from standalone composers.
<VeltCommentDialogComposer
  targetComposerElementId="my-composer"
  context={{ projectId: 'abc123', section: 'header' }}
/>

Improvements

  • [Comments]: Updated composerTextChange event to include the full draft annotation object and targetComposerElementId. Access tagged users, attachments, recordings, context, and assign-to data without additional API calls.
// Using Hooks
const composerTextChangeEvent = useCommentEventCallback('composerTextChange');

useEffect(() => {
  if (composerTextChangeEvent) {
    console.log(composerTextChangeEvent.text);
    console.log(composerTextChangeEvent.annotation);
    console.log(composerTextChangeEvent.targetComposerElementId);
  }
}, [composerTextChangeEvent]);

// Using API methods
const commentElement = client.getCommentElement();
commentElement.on('composerTextChange').subscribe((event) => {
  console.log(event.text);
  console.log(event.annotation);
  console.log(event.targetComposerElementId);
});
  • [Notifications]: Fixed notification panel settings accordion wireframes to properly forward custom trigger and content templates to child components.

Bug Fixes

  • [Comments]: Fixed assignToType to correctly respect values set via attribute or API without being overridden by hardcoded defaults.
  • [Comments]: Fixed formatted text (bold, italic, underline, strikethrough) to preserve formatting on submit and edit.
5.0.0-beta.14
February 10, 2026

New Features

  • [Comments]: Added page mode composer context APIs to pass context when opening the sidebar via the comment tool. When enabled, clicking the comment tool opens the sidebar with the page mode composer and passes configured context automatically.
// Using API methods
import { useCommentUtils, VeltCommentTool } from '@veltdev/react';

const commentElement = useCommentUtils();

// Enable context passing mode
commentElement.enableContextInPageModeComposer();

// Set context with target element
commentElement.setContextInPageModeComposer({
  context: { projectId: 'abc123', section: 'header' },
  targetElementId: 'my-target-element'
});

// Focus the composer programmatically
commentElement.focusPageModeComposer();

// Clear context
commentElement.clearPageModeComposerContext();

// Disable context passing mode
commentElement.disableContextInPageModeComposer();


// Using props
<VeltCommentTool
  contextInPageModeComposer={true}
  context={{ section: 'header', elementId: 'nav-menu' }}
/>
  • [Comments]: Added setAssignToType() method to switch the assignment UI between dropdown and checkbox modes. Checkbox mode allows quick self-assignment with a toggle.
// Using Hooks
import { useCommentUtils, VeltComments } from '@veltdev/react';

const commentElement = useCommentUtils();

// Use dropdown mode (default)
commentElement.setAssignToType({ type: 'dropdown' });

// Use checkbox mode for quick self-assignment
commentElement.setAssignToType({ type: 'checkbox' });


// Using props
<VeltComments assignToType="checkbox" />
  • [Comments]: Added “Assigned to me” filter option in the sidebar to filter comments by assignment.
import { VeltCommentsSidebarWireframe } from '@veltdev/react';

<VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content>
  <VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content.FilterAssignedToMe />
</VeltCommentsSidebarWireframe.MinimalFilterDropdown.Content>
  • [Comments]: Added new event types to track comment tool and sidebar button clicks. Subscribe to these events to access context data for analytics and custom workflows.
// Using Hooks
import { useCommentEventCallback } from '@veltdev/react';
import { useEffect } from 'react';

const commentToolClickEvent = useCommentEventCallback('commentToolClicked');

useEffect(() => {
  if (commentToolClickedEvent) {
    console.log('Context:', commentToolClickedEvent.context);
    console.log('Target Element ID:', commentToolClickedEvent.targetElementId);
  }
}, [commentToolClickedEvent]);

const sidebarButtonClickedEvent = useCommentEventCallback('sidebarButtonClicked');

useEffect(() => {
  if (sidebarButtonClickedEvent) {
    console.log('Sidebar button clicked');
  }
}, [sidebarButtonClickedEvent]);

// Using API methods
import { useVeltClient } from '@veltdev/react';

const { client } = useVeltClient();
const commentElement = client.getCommentElement();

commentElement.on('commentToolClicked').subscribe((event) => {
  console.log('Context:', event.context);
  console.log('Target Element ID:', event.targetElementId);
});

commentElement.on('sidebarButtonClicked').subscribe((event) => {
  console.log('Sidebar button clicked');
});
  • [Comments]: Added readOnly prop to control read-only mode at the component level. The local prop takes precedence over global settings when explicitly set.
import { VeltCommentComposer, VeltInlineCommentsSection } from '@veltdev/react';

<VeltCommentComposer readOnly={true} />

<VeltInlineCommentsSection
  targetElementId="my-element"
  readOnly={true}
/>
  • [Comments]: Added wireframe component to customize the assign button on thread cards.
import { VeltCommentDialogWireframe } from '@veltdev/react';

<VeltCommentDialogWireframe.ThreadCard.AssignButton />
  • [Comments]: Added wireframe component to customize the edit composer within comment thread cards.
import { VeltCommentDialogWireframe } from '@veltdev/react';

<VeltCommentDialogWireframe.ThreadCard.EditComposer />
  • [Comments]: Added reaction pin component to pin specific reactions and exclude them from the general list.
import { VeltCommentDialogWireframe } from '@veltdev/react';

<VeltCommentDialogWireframe.ThreadCard>
  <VeltCommentDialogWireframe.ThreadCard.ReactionPin reactionId="thumbs-up" />
  <VeltCommentDialogWireframe.ThreadCard.ReactionPin reactionId="heart" />

  <VeltCommentDialogWireframe.ThreadCard.Reactions
    excludeReactionIds={['thumbs-up', 'heart']}
  />

  <VeltCommentDialogWireframe.ThreadCard.ReactionTool
    excludeReactionIds={['thumbs-up', 'heart']}
  />
</VeltCommentDialogWireframe.ThreadCard>
  • [Comments]: Added resolvedByUser property on CommentAnnotation to access the full user object of who resolved a comment.

Improvements

  • [Comments]: Renamed targetElementId to targetComposerElementId on VeltCommentComposer for clarity.
import { VeltCommentComposer } from '@veltdev/react';

// Before (deprecated)
<VeltCommentComposer targetElementId="my-composer" />

// After (required)
<VeltCommentComposer targetComposerElementId="my-composer" />
  • [Comments]: Added CSS class .velt-assign-dropdown--checkbox-icon-selected to style the checkbox selected state.

Bug Fixes

  • [Comments]: Fixed cursor jumping when clicking autocomplete tool buttons. Text now inserts at the correct cursor position.
  • [Comments]: Fixed actions menu visibility so it remains visible when the assignment dropdown is opened.
  • [Comments]: Added “Assign” tooltip to the assignment button in thread cards.
  • [Comments]: Fixed “Assign To” label capitalization to “Assign to”.
  • [Reactions]: Added .velt-reaction-pin--no-reactions CSS class for styling empty reaction pins.
  • [Comments]: Fixed autocomplete panel viewport height to respect custom itemSize from autoCompleteScrollConfig.
  • [Comments]: Fixed attachment metadata handling to use fallback values when metadata is unavailable.
  • [Comments]: Fixed read-only state management so local readOnly props are not overridden by global state changes.
  • [Reactions]: Fixed reactions panel to return an empty array on error instead of default emojis.
  • [Comments]: Fixed reactionId prop on VeltCommentDialogWireframe.ThreadCard.ReactionPin to properly convert to dashed-case in React.
5.0.0-beta.13
February 10, 2026

New Features

  • [Notifications]: Added ability to enable organization-level notification settings. This allows you to configure notifications once for all documents in an organization instead of per document.
  <VeltNotificationsPanel
    enableSettingsAtOrganizationLevel={true}
    settings={true}
  />
  {/* or */}
  <VeltNotificationsTool
    enableSettingsAtOrganizationLevel="true"
    settings={true}
  />

// Using API methods
const notificationElement = client.getNotificationElement();
// Enable organization-level settings
notificationElement.enableSettingsAtOrganizationLevel();

// Disable organization-level settings
notificationElement.disableSettingsAtOrganizationLevel();
5.0.0-beta.12
February 6, 2026

Improvements

  • [Comments]: Comments sidebar group-by views now display “Unassigned” for annotations without assignees and “Untagged” for annotations without tagged users.

Bug Fixes

  • [Comments]: Fixed an issue where image attachments in comment dialog were not opening in a lightbox view.
  • [Comments]: Fixed an issue where sometimes user mentions did not include the leading @ symbol in display text.
  • [Comments]: Fixed an issue where the recorder control panel in comment dialog composer did not appear when a valid comment dialog ID was not present in component configuration.
  • [Comments]: Fixed an issue where assignment and private comment options did not respect explicit configuration in sidebar mode.
  • [Comments]: Fixed an issue where the comment dialog internal tag was changed from snippyly-comment-dialog to velt-comment-dialog-internal for correct sidebar focus and keyboard behavior.
5.0.0-beta.11
February 4, 2026

Improvements

  • [Comments]: Added ability to enable/disable Private Comments feature in Velt Console
5.0.0-beta.10
February 3, 2026

Improvements

  • [Comments]: Added batchedPerDocument mode for getCommentAnnotationsCount() that makes the query more efficient by up to 80% while maintaining per-document granularity. Very useful for UIs that need to display comment counts for 100 documents or less on the same page.
// Using hook
const commentElement = useCommentUtils();
const counts = commentElement.getCommentAnnotationsCount({
  documentIds: ['doc-1', 'doc-2', ..., 'doc-100'],
  batchedPerDocument: true
});

// Using API method
const client = useVeltClient();
const commentElement = client.getCommentElement();
const counts = commentElement.getCommentAnnotationsCount({
  documentIds: ['doc-1', 'doc-2', ..., 'doc-100'],
  batchedPerDocument: true,
  debounceMs: 5000
});
Return Format:
{
  data: {
    "doc-1": { total: 10, unread: 2 },
    "doc-2": { total: 15, unread: 5 }
  }
}
5.0.0-beta.9
January 31, 2026

Bug Fixes

  • [Comments]: Fixed draft mode not working properly. Draft content is now preserved when the dialog is closed and the shake animation now works as expected.
  • [Comments]: Fixed context property access in velt-data elements. Templates can now access context properties using {context.propertyName} patterns.
  • [Comments]: Fixed edit mode state persisting after dialog close. Reopening the dialog now shows the normal view instead of the edit composer.
  • [Comments]: Fixed text reappearing when using select-all-and-delete in edit mode composer. Users can now properly delete all text in edit mode.
  • [Comments]: Fixed links in comment body not clickable. Clicking links in comment text now opens them in a new tab.
  • [Comments]: Fixed paste handling. Pasting a URL over selected text creates a hyperlink, multiline text preserves line breaks, and images paste as attachments.
  • [Comments]: Fixed ghost comment banners not displaying. “Comment is syncing…” messages now properly show while annotation data is loading.
  • [Comments]: Fixed priority selection not working on new annotations. Users can now set priority before submitting the first comment.
  • [Comments]: Fixed email detection after @ symbol. Typing @user@example.com and pressing space now creates an email mention.
  • [Comments]: Fixed recording in progress flag not clearing. Dialog now properly closes on click outside after recording finishes.
  • [Comments]: Fixed links and @here mentions not highlighted in comment text. URLs are now styled as clickable links and @here mentions are properly highlighted.
5.0.0-beta.8
January 30, 2026

New Features

  • [Comments]: Introducing Private Comments feature: Added updateVisibility() method to programmatically set comment access (public, organizationPrivate, or restricted). Learn more
// Using hook
const commentElement = useCommentUtils();

// Set comment to organization-only
commentElement.updateVisibility({
  annotationId: "annotationId",
  type: 'organizationPrivate',
  organizationId: 'org-123'
});

// Set comment to private (specific users)
commentElement.updateVisibility({
  annotationId: "annotationId",
  type: 'restricted',
  userIds: ['user-1', 'user-2']
});

// Set comment to public
commentElement.updateVisibility({
  annotationId: "annotationId",
  type: 'public'
});

// Using API method
const client = useVeltClient();
const commentElement = client.getCommentElement();
commentElement.updateVisibility({
  annotationId: "annotationId",
  type: 'organizationPrivate',
  organizationId: 'org-123'
});

Bug Fixes

  • [Comments]: Fixed mentioned users not receiving notifications. Users @mentioned in comments now correctly receive notifications.
  • [Comments]: Fixed notification action type validation. Clients only receive data for valid event types.
  • [Comments]: Fixed status reset when deleting comments. Status now only resets when current status is terminal.
5.0.0-beta.7
January 28, 2026

New Features

  • [Comments]: Added addCommentAnnotationDraft event to dynamically set context when creating comment annotations. Triggered before addCommentAnnotation event clicks on the comment tool and the composer is rendered.
// Using hook
const addCommentAnnotationDraftEvent = useCommentEventCallback('addCommentAnnotationDraft');

useEffect(() => {
    if (addCommentAnnotationDraftEvent?.addContext) {
        addCommentAnnotationDraftEvent.addContext({
            questionId: '123',
            questionText: 'What is the capital of France?',
        });
    }
}, [addCommentAnnotationDraftEvent]);

// Using API method
const client = useVeltClient();
const commentElement = client.getCommentElement();
commentElement.on('addCommentAnnotationDraft').subscribe((event) => {
    if (event?.addContext) {
        event.addContext({
            questionId: '123',
            questionText: 'What is the capital of France?',
        });
    }
});

Improvements

  • [Comments]: Added setContextProvider method to set a global context provider for all comment annotations. Also added useSetContextProvider hook for React applications.
// Using hook
import { useCallback, useEffect } from 'react';
import { useSetContextProvider } from '@veltdev/react';

const contextProvider = useCallback((documentId, location) => {
    return {
        questionId: '123',
        questionText: 'What is the capital of France?',
    }
}, []);

const { setContextProvider } = useSetContextProvider();

useEffect(() => {
    if (setContextProvider && contextProvider) {
        setContextProvider(contextProvider);
    }
}, []);

// Using API method
const client = useVeltClient();
const commentElement = client.getCommentElement();
commentElement.setContextProvider((documentId, location) => {
    return {
        questionId: '123',
        questionText: 'What is the capital of France?',
    }
});
5.0.0-beta.6
January 28, 2026

Bug Fixes

  • [Core]: Fixed package integrity issue in v5.0.0-beta.5.
5.0.0-beta.5
January 28, 2026

Bug Fixes

  • [Comments]: Fixed page mode and multi-thread annotation ID not found error. Page mode and multi-thread comments now work as expected.
  • [Comments]: Fixed updateOverlayPosition function not triggering. Comment dialog now opens in the correct position.
  • [Comments]: Fixed unread status issues in inline and focused thread modes. Annotations are now marked as read when opened or clicked.
  • [Comments]: Fixed three-dot menu not visible in sidebar.
  • [Comments]: Fixed composer not being focused when opened.
  • [Comments]: Fixed comments navigating on click. Comments now only navigate when the navigation button is clicked.
5.0.0-beta.4
January 23, 2026

Bug Fixes

  • [Comments]: Fixed lastUpdated timestamp not being updated when changing context in comment annotation via SDK. Ensures context updates are properly synced to other users.
5.0.0-beta.3
January 22, 2026

Improvements

  • [Core]: Added robustness to initialization when VeltProvider was re-rendered multiple times over a slow network.

Bug Fixes

  • [Comments]: Refactored submitComment method to fix resolver issue for velt-comment-composer. Now follows the standard comment submission flow.
  • [Comments]: Fixed unread status not updating correctly in bottom sheet. This was a regression in v5.
  • [Comments]: Fixed navigation button not working properly. This was a regression in v5.
  • [Comments]: Fixed disable recording option not working in velt-comment-composer. This was a regression in v5.
5.0.0-beta.2
January 22, 2026

New Features

  • [Core]: Added globalStyles option to control whether Velt’s global CSS is loaded. Set to false to disable default styles when implementing custom theming.
// Using VeltProvider
<VeltProvider apiKey='API_KEY' config={{
    globalStyles: false
}}>
    {/* Your app content */}
</VeltProvider>

// Using API method
const client = useVeltClient();
client.initConfig('API_KEY', {
  globalStyles: false
});
  • [Comments]: Added submitComment(targetElementId) method to programmatically trigger comment submission. Enables custom buttons or keyboard shortcuts for submitting comments.

<VeltCommentComposer targetElementId="composer-1" />
<VeltCommentDialogComposer targetElementId="composer-2" />

// Using hook
const commentElement = useCommentUtils();
commentElement.submitComment('composer-1');

// Using API method
const client = useVeltClient();
const commentElement = client.getCommentElement();
commentElement.submitComment('composer-1');
  • [Comments]: Added placeholder prop to customize input placeholder text in comment composer. Overrides default placeholders. Learn more
<VeltCommentComposer placeholder="Share your thoughts..." />
<VeltCommentDialogComposer placeholder="Add a comment..." />
  • [Comments]: Added composerTextChange event that fires when text changes in any comment composer. Enables features like auto-save drafts, character counters, or real-time validation. Learn more
// Using hook
const composerTextChangeEvent = useCommentEventCallback('composerTextChange');
useEffect(() => {
    if (composerTextChangeEvent) {
        console.log('Text changed:', composerTextChangeEvent.text);
    }
}, [composerTextChangeEvent]);

// Using API method
const client = useVeltClient();
const commentElement = client.getCommentElement();
commentElement.on('composerTextChange').subscribe((event) => {
    console.log('Text changed:', event.text);
});
5.0.0-beta.1
January 21, 2026

Bug Fixes

Comment Dialog Primitives

Released 115+ primitive components for building custom comment dialogs. Each subcomponent can now be used independently without requiring the full dialog structure.
// Pattern 1: ID-Based (Standalone)
<VeltCommentDialogHeader annotationId="abc123" />
<VeltCommentDialogComposer annotationId="abc123" />

// Pattern 2: Context Wrapper
<VeltCommentDialogContextWrapper annotationId="abc123">
  <VeltCommentDialogHeader />
  <VeltCommentDialogComposer />
  <VeltCommentDialogBody />
</VeltCommentDialogContextWrapper>
Available Components:
  • Header/Body: Header, Body, CloseButton
  • Thread: ThreadCard with Avatar, Name, Time, Message, Reactions, Recordings, Reply, Options, and more
  • Composer: Composer, ComposerInput, ComposerActionButton, ComposerAttachmentButton, ComposerRecorderButton, ComposerRecorderPlayer, ComposerFiles
  • Dropdowns: StatusDropdown, PriorityDropdown, OptionsDropdown, CustomAnnotationDropdown (each with full sub-component breakdown)
  • Additional: ReplyAvatars, AssigneeBanner, ResolveButton, UnresolveButton, CopyLink, DeleteButton, PrivateBanner, NavigationButton, and 90+ more
View full documentation → | API Methods | Data Models