Skip to main content

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 text mode prop to false to hide the default text comment tool.
<VeltProvider apiKey="API_KEY">
  <VeltComments textMode={false} />
</VeltProvider>

Step 2: Install the Velt DraftJS extension

npm i @veltdev/draftjs-velt-comments draft-js

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

Use DraftJSVeltEditor instead of the standard DraftJS Editor. This wrapper component handles the DraftJS decorator setup, content change detection, and annotation tracking.
import { useState } from 'react';
import { EditorState } from 'draft-js';
import { DraftJSVeltEditor } from '@veltdev/draftjs-velt-comments';

function DraftJSEditor() {
  const [editorState, setEditorState] = useState(() =>
    EditorState.createEmpty()
  );

  return (
    <DraftJSVeltEditor
      editorState={editorState}
      onChange={setEditorState}
      placeholder="Start typing..."
    />
  );
}

Step 4: Add a comment button to your DraftJS editor

  • Add a button that users can click after selecting text in the DraftJS editor.
  • Use onMouseDown with preventDefault() so the browser does not move focus away from the editor and clear the current text selection.
import { useCallback, useEffect, useRef, useState } from 'react';
import { EditorState } from 'draft-js';
import {
  DraftJSVeltEditor,
  addComment,
} from '@veltdev/draftjs-velt-comments';

function DraftJSEditor() {
  const [editorState, setEditorState] = useState(() =>
    EditorState.createEmpty()
  );

  const editorRef = useRef({ editorState, setEditorState });

  useEffect(() => {
    editorRef.current = { editorState, setEditorState };
  }, [editorState]);

  const handleAddComment = useCallback(() => {
    addComment({ editor: editorRef.current });
  }, []);

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

      <DraftJSVeltEditor
        editorState={editorState}
        onChange={setEditorState}
        placeholder="Start typing..."
      />
    </div>
  );
}

Step 5: Call addComment to add a comment

  • Call this method to add a comment to selected text in the DraftJS editor.
  • Params: AddCommentRequest
    • editor: DraftJS editor wrapper object with { editorState, setEditorState }.
    • editorId: Id of the editor. Use this if you have multiple DraftJS editors on the same page. (optional)
    • context: Add custom metadata to the Comment Annotation. Learn more. (optional)
import { addComment } from '@veltdev/draftjs-velt-comments';

const addCommentRequest = {
  editor,
  editorId: 'EDITOR_ID',
  context: {
    storyId: 'story-id',
    storyName: 'story-name',
  },
};

addComment(addCommentRequest);

Step 6: Render comments in DraftJS editor

  • Get comment data from Velt SDK and render it in the DraftJS editor.
  • Params: RenderCommentsRequest
    • editor: DraftJS editor wrapper object with { editorState, setEditorState }.
    • editorId: Id of the editor. Use this if you have multiple DraftJS editors on the same page. (optional)
    • commentAnnotations: Array of Comment Annotation objects.
import { useEffect, useRef, useState } from 'react';
import { EditorState } from 'draft-js';
import { useCommentAnnotations } from '@veltdev/react';
import {
  DraftJSVeltEditor,
  renderComments,
} from '@veltdev/draftjs-velt-comments';

function DraftJSEditor() {
  const annotations = useCommentAnnotations();
  const [editorState, setEditorState] = useState(() =>
    EditorState.createEmpty()
  );

  const editorRef = useRef({ editorState, setEditorState });

  useEffect(() => {
    editorRef.current = { editorState, setEditorState };
  }, [editorState]);

  useEffect(() => {
    renderComments({
      editor: editorRef.current,
      editorId: 'EDITOR_ID',
      commentAnnotations: annotations ?? [],
    });
  }, [annotations]);

  return (
    <DraftJSVeltEditor
      editorState={editorState}
      onChange={setEditorState}
    />
  );
}

Step 7: Persist DraftJS content without Velt comment entities (optional)

  • When saving editor content to your backend, remove Velt comment entities to keep your stored content clean.
  • Use exportContentStateWithoutComments before converting DraftJS content to raw JSON.
import { convertToRaw } from 'draft-js';
import { exportContentStateWithoutComments } from '@veltdev/draftjs-velt-comments';

const cleanContent = exportContentStateWithoutComments(
  editorState.getCurrentContent()
);

const rawContent = convertToRaw(cleanContent);

Step 8: Style the commented text

  • Style the commented text by adding CSS for the velt-comment-text element.
velt-comment-text {
  background-color: rgba(255, 255, 0, 0.3);
  border-bottom: 2px solid #ffcc00;
  cursor: pointer;
}

velt-comment-text:hover {
  background-color: rgba(255, 255, 0, 0.5);
}

velt-comment-text.velt-comment-selected {
  background-color: rgba(255, 255, 0, 0.5);
}

Complete Example

APIs

DraftJSVeltEditor

A wrapper around the DraftJS Editor component that automatically handles decorator setup, content change detection, and Velt annotation context updates.
  • Props: DraftJSVeltEditorProps
    • editorState: Current DraftJS editor state.
    • onChange: Callback when the editor state changes.
    • editorId: Optional editor ID for multi-editor scenarios.
    • All other standard DraftJS Editor props are forwarded.
import { DraftJSVeltEditor } from '@veltdev/draftjs-velt-comments';

<DraftJSVeltEditor
  editorState={editorState}
  onChange={setEditorState}
  editorId="my-editor"
  placeholder="Start typing..."
/>

addComment()

Creates a comment annotation for the currently selected text in the editor.
import { addComment } from '@veltdev/draftjs-velt-comments';

const handleAddComment = () => {
  addComment({ editor, editorId: 'my-editor' });
};

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

renderComments()

Renders and highlights comment annotations in the DraftJS editor.
import { renderComments } from '@veltdev/draftjs-velt-comments';

useEffect(() => {
  renderComments({
    editor: editorRef.current,
    editorId: 'my-editor',
    commentAnnotations,
  });
}, [commentAnnotations]);

exportContentStateWithoutComments()

Returns a DraftJS ContentState without Velt comment entities. Use it before saving content outside Velt.
import { convertToRaw } from 'draft-js';
import { exportContentStateWithoutComments } from '@veltdev/draftjs-velt-comments';

const cleanContent = exportContentStateWithoutComments(
  editorState.getCurrentContent()
);
const rawContent = convertToRaw(cleanContent);