Skip to main content
The SuperDoc integration renders Velt comment highlights as view-only overlay elements positioned over the commented text. It does not write Velt comment marks into your DOCX content. Comment anchors are stored as a durable text and occurrence pair, then resolved against the live SuperDoc document whenever comments render.

Setup

Step 1: 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 textMode prop to false to hide the default text comment tool.
import { VeltComments, VeltProvider } from '@veltdev/react';

<VeltProvider apiKey="API_KEY">
  <VeltComments textMode={false} />
</VeltProvider>

Step 2: Install the Velt SuperDoc extension

npm i @veltdev/superdoc-velt-comments @harbour-enterprises/superdoc
SuperDoc is browser-only because it touches window and the DOM. Import its stylesheet globally, then dynamically import the SuperDoc SDK and Velt extension inside a client-side effect.
import '@harbour-enterprises/superdoc/style.css';

Step 3: Configure the SuperDoc editor with the Velt Comments extension

Create the SuperDoc editor, disable SuperDoc’s built-in comments, then attach SuperDocVeltComments from the editor’s onReady callback.
import { useEffect, useRef, useState } from 'react';
import { useCommentAnnotations } from '@veltdev/react';
import type {
  AttachedExtension,
  SuperDocInstance,
} from '@veltdev/superdoc-velt-comments';

const EDITOR_ID = 'my-doc';

function SuperDocEditor() {
  const hostRef = useRef<HTMLDivElement | null>(null);
  const superdocRef = useRef<SuperDocInstance | null>(null);
  const extensionRef = useRef<AttachedExtension | null>(null);
  const [instance, setInstance] = useState<SuperDocInstance | null>(null);
  const annotations = useCommentAnnotations();

  useEffect(() => {
    if (!hostRef.current || superdocRef.current) return;

    let cancelled = false;
    const host = hostRef.current;

    Promise.all([
      import('@harbour-enterprises/superdoc'),
      import('@veltdev/superdoc-velt-comments'),
    ]).then(([{ SuperDoc }, wrapper]) => {
      if (cancelled) return;

      superdocRef.current = new SuperDoc({
        selector: host,
        toolbar: '#superdoc-toolbar',
        document: '/sample.docx',
        documentMode: 'editing',
        modules: { comments: false },
        onReady: () => {
          if (cancelled || !superdocRef.current) return;

          extensionRef.current = wrapper.SuperDocVeltComments
            .configure({ editorId: EDITOR_ID })
            .attach(superdocRef.current);
          setInstance(superdocRef.current);
        },
      });
    });

    return () => {
      cancelled = true;
      extensionRef.current?.detach();
      extensionRef.current = null;
      superdocRef.current?.destroy();
      superdocRef.current = null;
      setInstance(null);
    };
  }, []);

  useEffect(() => {
    if (!instance) return;

    import('@veltdev/superdoc-velt-comments').then(({ renderComments }) => {
      renderComments({
        instance,
        commentAnnotations: annotations ?? [],
      });
    });
  }, [instance, annotations]);

  return (
    <>
      <div id="superdoc-toolbar" />
      <div ref={hostRef} style={{ width: '100%', height: '100vh' }} />
    </>
  );
}

Step 4: Add a comment button to your SuperDoc editor

Add a button users can click after selecting text in the SuperDoc editor. Use onMouseDown with preventDefault() so clicking the button does not clear the current editor selection before addComment reads it. Keep the actual addComment call in onClick.
const handleAddComment = async () => {
  if (!instance) return;

  const { addComment } = await import('@veltdev/superdoc-velt-comments');
  const result = await addComment({ instance });

  if (!result) {
    console.warn('Select text in the document before adding a comment.');
  }
};

<button
  onMouseDown={(event) => event.preventDefault()}
  onClick={handleAddComment}
>
  Add Comment
</button>

Step 5: Call addComment to add a comment

  • Call this method to add a comment to selected text in the SuperDoc editor.
  • Params: AddCommentArgs. It has the following properties:
    • instance: SuperDoc editor instance returned by new SuperDoc(...).
  • Returns: Promise<AddCommentResult | null>. It returns null if no text is selected or Velt is not loaded.
import { addComment } from '@veltdev/superdoc-velt-comments';

const result = await addComment({ instance });
To scope comments to a specific editor on pages with multiple SuperDoc instances, pass an editor id when attaching the extension:
SuperDocVeltComments.configure({ editorId: 'EDITOR_ID' }).attach(superdoc);

Step 6: Render comments in the SuperDoc editor

  • Get the comment data from Velt SDK and render it in the SuperDoc editor.
  • Params: RenderCommentsArgs. It has the following properties:
    • instance: SuperDoc editor instance.
    • commentAnnotations: Array of Comment Annotation objects.
import { useEffect } from 'react';
import { useCommentAnnotations } from '@veltdev/react';
import { renderComments } from '@veltdev/superdoc-velt-comments';

const commentAnnotations = useCommentAnnotations();

useEffect(() => {
  if (!instance) return;

  renderComments({
    instance,
    commentAnnotations: commentAnnotations ?? [],
  });
}, [instance, commentAnnotations]);
Highlights are view-only. The library re-derives each highlight from its TextEditorConfig anchor and remaps live ranges as the document changes. You do not need to call renderComments on every edit, scroll, zoom, or resize. Re-run it when Velt’s annotation list changes.

Step 7: Clean up the SuperDoc extension

SuperDocVeltComments.configure(...).attach(instance) returns an AttachedExtension. Call detach() in your effect cleanup to remove listeners, clear per-instance state, and remove overlay elements before destroying the editor.
return () => {
  extensionRef.current?.detach();
  extensionRef.current = null;
  superdocRef.current?.destroy();
};

Step 8: Style the commented text

  • You can style commented text by adding CSS for the velt-comment-text element.
  • SuperDoc highlights are light-DOM overlay elements inside div.velt-superdoc-overlay-root, so a global stylesheet can reach them.
  • The default highlight rules use inline !important styles, so overrides should use !important.
velt-comment-text {
  background-color: rgba(255, 212, 0, 0.4) !important;
  border-bottom: 2px solid #ffd400 !important;
  cursor: pointer;
}

velt-comment-text:hover {
  background-color: rgba(255, 212, 0, 0.6) !important;
}

velt-comment-text[comment-selected="true"],
velt-comment-text.velt-comment-selected {
  background-color: rgba(255, 212, 0, 0.7) !important;
}

Complete Example

APIs

SuperDocVeltComments

Creates the Velt Comments extension for a SuperDoc editor. Use SuperDocVeltComments.configure(...).attach(instance) to attach it to an editor instance.
import { SuperDocVeltComments } from '@veltdev/superdoc-velt-comments';

const attached = SuperDocVeltComments
  .configure({ editorId: 'my-doc' })
  .attach(superdoc);

attached.detach();

addComment()

Creates a comment annotation for the currently selected text in the SuperDoc editor.
  • Signature: async (args: AddCommentArgs) => Promise<AddCommentResult | null>
  • Params: args: AddCommentArgs
  • Returns: Promise<AddCommentResult | null>; see AddCommentResult.
import { addComment } from '@veltdev/superdoc-velt-comments';

const result = await addComment({ instance });

renderComments()

Renders and updates Velt comment highlights in the SuperDoc editor.
import { renderComments } from '@veltdev/superdoc-velt-comments';

renderComments({
  instance,
  commentAnnotations: annotations ?? [],
});