> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velt.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# CodeMirror Setup

<img src="https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/Add-Text-Comments.gif?s=1da499b73486c2acd4667b517baab389" alt="" width="1280" height="720" data-path="gifs/Add-Text-Comments.gif" />

## 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.

<Tabs>
  <Tab title="React / Next.js">
    ```js theme={null}
    <VeltProvider apiKey="API_KEY">
      <VeltComments textMode={false} />
    </VeltProvider>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <body>
      <velt-comments text-mode="false"></velt-comments>
    </body>
    ```
  </Tab>
</Tabs>

#### Step 2: Install the Velt CodeMirror extension

```bash theme={null}
npm i @veltdev/codemirror-velt-comments
```

#### Step 3: Configure the CodeMirror editor with the Velt Comments extension

<Tabs>
  <Tab title="React / Next.js">
    ```js theme={null}
    import { EditorView, basicSetup } from 'codemirror';
    import { CodemirrorVeltComments } from '@veltdev/codemirror-velt-comments';

    const view = new EditorView({
      doc: 'Your initial content here',
      extensions: [
        basicSetup,
        CodemirrorVeltComments(),
        // ... other extensions
      ],
      parent: editorRef.current,
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    import { EditorView, basicSetup } from 'codemirror';
    import { CodemirrorVeltComments } from '@veltdev/codemirror-velt-comments';

    const editorView = new EditorView({
      doc: 'Your initial content here',
      extensions: [
        basicSetup,
        CodemirrorVeltComments(),
        // ... other extensions
      ],
      parent: document.querySelector('#editor'),
    });
    ```
  </Tab>
</Tabs>

#### Step 4: Add a comment button to your CodeMirror editor

Add a button that users can click to add comments after selecting text.

**Important:** When clicking a button, the browser moves focus to the button which clears the editor selection. You need to save the selection on `mousedown` (before focus changes) and restore it before adding the comment.

<Tabs>
  <Tab title="React / Next.js">
    ```js theme={null}
    import { useRef, useState, useEffect } from 'react';
    import { EditorView, basicSetup } from 'codemirror';
    import { CodemirrorVeltComments, addComment } from '@veltdev/codemirror-velt-comments';

    function CodeMirrorEditor() {
      const editorRef = useRef(null);
      const [editorView, setEditorView] = useState(null);
      const savedSelectionRef = useRef(null);
      const annotations = useCommentAnnotations();

      useEffect(() => {
        if (!editorRef.current) return;

        const view = new EditorView({
          doc: 'Your initial content here',
          extensions: [
            basicSetup,
            CodemirrorVeltComments(),
          ],
          parent: editorRef.current,
        });

        setEditorView(view);
        return () => view.destroy();
      }, []);

      const saveSelection = () => {
        if (editorView) {
          const { from, to } = editorView.state.selection.main;
          if (from !== to) {
            savedSelectionRef.current = { from, to };
          }
        }
      };

      const handleAddComment = () => {
        if (editorView) {
          if (savedSelectionRef.current) {
            const { from, to } = savedSelectionRef.current;
            if (from !== to) {
              editorView.dispatch({
                selection: { anchor: from, head: to }
              });
            }
          }
          addComment({ editor: editorView });
          savedSelectionRef.current = null;
        }
      };

      return (
        <div>
          <button
            onMouseDown={(e) => {
              e.preventDefault();
              saveSelection();
            }}
            onClick={handleAddComment}
          >
            Add Comment
          </button>
          <div ref={editorRef} />
        </div>
      );
    }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <!-- HTML Structure -->
    <button id="add-comment-btn">Add Comment</button>
    <div id="editor"></div>
    ```

    ```js theme={null}
    import { EditorView, basicSetup } from 'codemirror';
    import { CodemirrorVeltComments, addComment } from '@veltdev/codemirror-velt-comments';

    const editorView = new EditorView({
      doc: 'Your initial content here',
      extensions: [
        basicSetup,
        CodemirrorVeltComments(),
      ],
      parent: document.querySelector('#editor'),
    });

    let savedSelection = null;

    const saveSelection = () => {
      if (editorView) {
        const { from, to } = editorView.state.selection.main;
        if (from !== to) {
          savedSelection = { from, to };
        }
      }
    };

    const addCommentToEditor = () => {
      if (editorView) {
        if (savedSelection && savedSelection.from !== savedSelection.to) {
          editorView.dispatch({
            selection: { anchor: savedSelection.from, head: savedSelection.to }
          });
        }
        addComment({ editor: editorView });
        savedSelection = null;
      }
    };

    const addCommentBtn = document.getElementById('add-comment-btn');
    addCommentBtn.addEventListener('mousedown', (e) => {
      e.preventDefault();
      saveSelection();
    });
    addCommentBtn.addEventListener('click', addCommentToEditor);
    ```
  </Tab>
</Tabs>

#### Step 5: Call `addComment` to add a comment

* Call this method to add a comment to selected text in the CodeMirror editor. You can use this when the user clicks on the comment button or presses a keyboard shortcut.
* Params: [`AddCommentRequest`](/api-reference/sdk/models/data-models#addcommentrequest-4). It has the following properties:
  * `editor`: instance of the CodeMirror EditorView.
  * `editorId`: Id of the CodeMirror editor. Use this if you have multiple CodeMirror editors on the same page in your app. (optional)
  * `context`: Add any custom metadata to the Comment Annotation. [Learn more](/async-collaboration/comments/customize-behavior#metadata). (optional)

<Tabs>
  <Tab title="React / Next.js">
    ```js theme={null}
    import { addComment } from '@veltdev/codemirror-velt-comments';

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

    addComment(addCommentRequest);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    import { addComment } from '@veltdev/codemirror-velt-comments';

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

    addComment(addCommentRequest);
    ```
  </Tab>
</Tabs>

#### Step 6: Render comments in CodeMirror editor

* Get the comment data from Velt SDK and render it in the CodeMirror editor.
* Params: [`RenderCommentsRequest`](/api-reference/sdk/models/data-models#rendercommentsrequest-4). It has the following properties:
  * `editor`: Instance of the CodeMirror EditorView.
  * `editorId`: Id of the CodeMirror editor. Use this if you have multiple CodeMirror editors on the same page in your app. (optional)
  * `commentAnnotations`: Array of Comment Annotation objects.

<Tabs>
  <Tab title="React / Next.js">
    ```js theme={null}
    import { renderComments } from '@veltdev/codemirror-velt-comments';
    import { useCommentAnnotations } from '@veltdev/react';

    const annotations = useCommentAnnotations();

    useEffect(() => {
      if (editorView && annotations?.length) {
        const renderCommentsRequest = {
          editor: editorView,
          editorId: 'EDITOR_ID',
          commentAnnotations: annotations,
        };
        renderComments(renderCommentsRequest);
      }
    }, [editorView, annotations]);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    import { renderComments } from '@veltdev/codemirror-velt-comments';

    const commentElement = Velt.getCommentElement();
    commentElement.getAllCommentAnnotations().subscribe((annotations) => {
      if (editorView && annotations?.length) {
        const renderCommentsRequest = {
          editor: editorView,
          editorId: 'EDITOR_ID',
          commentAnnotations: annotations,
        };
        renderComments(renderCommentsRequest);
      }
    });
    ```
  </Tab>
</Tabs>

#### Step 7: Persist Velt Comment Marks (optional)

* By default, Velt comment marks (`<velt-comment-text>`) are persisted in the CodeMirror editor by Velt SDK. When the editor loads and the Velt SDK initializes, the marks will be automatically added to the editor.
* If you plan to store the contents of the CodeMirror editor on your end with the comment marks already included, you can disable this feature.
* Default: `true`

```js theme={null}
const editorView = new EditorView({
  extensions: [
    CodemirrorVeltComments({
      persistVeltMarks: false,
    }),
    // ... other extensions
  ],
  parent: editorRef.current,
});
```

#### Step 8: Style the commented text

* You can style the commented text by adding CSS for the `velt-comment-text` element.

```css theme={null}
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);
}
```

## APIs

#### [CodemirrorVeltComments()](/api-reference/sdk/api/api-methods#codemirrorveltcomments)

Creates the Velt Comments extension for CodeMirror.

* Params: `config?:` [CodemirrorVeltCommentsConfig](/api-reference/sdk/models/data-models#codemirrorveltcommentsconfig)
  * `editorId?: string` - Unique identifier for this editor instance (for multi-editor scenarios)
  * `persistVeltMarks?: boolean` - Whether to persist Velt marks. Default: `true`
* Returns: CodeMirror `Extension`

<Tabs>
  <Tab title="React / Next.js">
    ```tsx theme={null}
    import { EditorView } from 'codemirror';
    import { CodemirrorVeltComments } from '@veltdev/codemirror-velt-comments';

    const view = new EditorView({
      extensions: [
        CodemirrorVeltComments({
          editorId: 'my-editor',
          persistVeltMarks: true,
        }),
      ],
      parent: editorRef.current,
    });
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```tsx theme={null}
    import { EditorView } from 'codemirror';
    import { CodemirrorVeltComments } from '@veltdev/codemirror-velt-comments';

    const editorView = new EditorView({
      extensions: [
        CodemirrorVeltComments({
          editorId: 'my-editor',
          persistVeltMarks: true,
        }),
      ],
      parent: document.body,
    });
    ```
  </Tab>
</Tabs>

#### [addComment()](/api-reference/sdk/api/api-methods#addcomment-4)

Creates a comment annotation for the currently selected text in the editor.

* Params:
  * `request:` [AddCommentRequest](/api-reference/sdk/models/data-models#addcommentrequest-4)
    * `editor: EditorView`
    * `editorId?: string`
    * `context?: object`
* Returns: `Promise<void>`

<Tabs>
  <Tab title="React / Next.js">
    ```tsx theme={null}
    import { addComment } from '@veltdev/codemirror-velt-comments';

    <button
      onMouseDown={(e) => {
        e.preventDefault();
        addComment({
          editor: editorView,
          editorId: 'my-editor',
          context: { customData: 'value' }
        });
      }}
    >
      Comment
    </button>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```tsx theme={null}
    import { addComment } from '@veltdev/codemirror-velt-comments';

    addComment({
      editor: editorView,
      editorId: 'my-editor',
      context: { customData: 'value' },
    });
    ```
  </Tab>
</Tabs>

#### [renderComments()](/api-reference/sdk/api/api-methods#rendercomments-4)

Renders and highlights comment annotations in the editor.

* Params:
  * `request:` [RenderCommentsRequest](/api-reference/sdk/models/data-models#rendercommentsrequest-4)
    * `editor: EditorView`
    * `editorId?: string`
    * `commentAnnotations?:` [CommentAnnotation\[\]](/api-reference/sdk/models/data-models#commentannotation)
* Returns: `void`

<Tabs>
  <Tab title="React / Next.js">
    ```tsx theme={null}
    import { useEffect } from 'react';
    import { renderComments } from '@veltdev/codemirror-velt-comments';
    import { useCommentAnnotations } from '@veltdev/react';

    const annotations = useCommentAnnotations();

    useEffect(() => {
      if (editorView && annotations) {
        renderComments({
          editor: editorView,
          editorId: 'my-editor',
          commentAnnotations: annotations,
        });
      }
    }, [editorView, annotations]);
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```tsx theme={null}
    import { renderComments } from '@veltdev/codemirror-velt-comments';

    const commentElement = Velt.getCommentElement();
    commentElement.getAllCommentAnnotations().subscribe((annotations) => {
      if (editorView && annotations) {
        renderComments({
          editor: editorView,
          editorId: 'my-editor',
          commentAnnotations: annotations,
        });
      }
    });
    ```
  </Tab>
</Tabs>
