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

# Lexical 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 Lexical extension

```bash theme={null}
npm install @veltdev/lexical-velt-comments @veltdev/client lexical
```

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

* Register the `CommentNode` and configure your Lexical editor.

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

    const initialConfig = {
      namespace: 'MyEditor',
      nodes: [CommentNode],
      onError: (error) => console.error(error),
    };

    function App() {
      return (
        <LexicalComposer initialConfig={initialConfig}>
          {/* Editor plugins */}
        </LexicalComposer>
      );
    }
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    import { createEditor } from 'lexical';
    import { registerRichText } from '@lexical/rich-text';
    import { CommentNode, addComment, renderComments } from '@veltdev/lexical-velt-comments';

    const editor = createEditor({
      namespace: 'MyEditor',
      nodes: [CommentNode],
      onError: (error) => {
        throw error;
      },
    });

    // Set the root element
    editor.setRootElement(document.querySelector('#editor'));

    // Register rich text support
    registerRichText(editor);
    ```
  </Tab>
</Tabs>

#### Step 4: Add a comment button

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

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

    function AddCommentPlugin() {
      const [editor] = useLexicalComposerContext();

      const handleAddComment = useCallback(() => {
        addComment({ editor });
      }, [editor]);

      return (
        <button onClick={handleAddComment}>
          Add Comment
        </button>
      );
    }
    ```
  </Tab>

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

    ```js theme={null}
    import { addComment } from '@veltdev/lexical-velt-comments';

    const addCommentBtn = document.getElementById('add-comment-btn');
    addCommentBtn.addEventListener('click', () => {
      addComment({ editor });
    });
    ```
  </Tab>
</Tabs>

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

* Call this method to add a comment to selected text in the Lexical editor. You can use this when the user clicks on a comment button or presses a keyboard shortcut.
* Params: [`AddCommentRequest`](/api-reference/sdk/models/data-models#addcommentrequest-3). It has the following properties:
  * `editor`: Instance of the Lexical Editor.
  * `editorId`: Id of the editor. Use this if you have multiple Lexical editors on the same page. (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/lexical-velt-comments';

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

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

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

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

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

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

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

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

    const annotations = useCommentAnnotations();

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

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

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

#### Step 7: Persist Editor Content Without Velt Marks (optional)

* When saving editor content to your backend, you may want to exclude Velt comment marks to keep the content clean.
* Use `exportJSONWithoutComments` to export the editor state as JSON without Velt comment nodes.

```js theme={null}
import { exportJSONWithoutComments } from '@veltdev/lexical-velt-comments';

// Get clean editor state JSON without Velt comment marks
const cleanState = exportJSONWithoutComments(editor);

// Save to your backend
localStorage.setItem('editor-content', JSON.stringify(cleanState));
```

#### Step 8: Style the commented text

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

## Complete Example

<Frame>
  <iframe src="https://sample-apps-lexical-comments-demo.vercel.app/" className="w-full" height="500px" />
</Frame>

## APIs

#### [CommentNode](/api-reference/sdk/models/data-models#commentnode)

A custom Lexical node used to wrap commented text with comment annotation metadata.

* Usage: Register the node with your Lexical editor so comment elements render correctly.

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

    const initialConfig = {
      namespace: 'MyEditor',
      nodes: [CommentNode],
      onError: console.error,
    };

    export default function Editor() {
      return <LexicalComposer initialConfig={initialConfig}>{/* plugins */}</LexicalComposer>;
    }
    ```
  </Tab>

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

    const editor = createEditor({
      namespace: 'MyEditor',
      nodes: [CommentNode],
      onError: (error) => {
        throw error;
      },
    });
    ```
  </Tab>
</Tabs>

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

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

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

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

    <button onClick={() => addComment({ editor, editorId: 'my-editor' })}>
      Comment
    </button>
    ```
  </Tab>

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

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

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

Renders and highlights comment annotations in the editor.

* Params:
  * `request:` [`RenderCommentsRequest`](/api-reference/sdk/models/data-models#rendercommentsrequest-3)
    * `editor: LexicalEditor`
    * `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/lexical-velt-comments';
    import { useCommentAnnotations } from '@veltdev/react';

    const annotations = useCommentAnnotations();

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

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

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

#### [exportJSONWithoutComments()](/api-reference/sdk/api/api-methods#exportjsonwithoutcomments)

Exports the editor state as serialized JSON while stripping out all comment nodes and normalizing adjacent text nodes.

* Params: `editor:` `LexicalEditor`
* Returns: `SerializedEditorState`

```tsx theme={null}
import { exportJSONWithoutComments } from '@veltdev/lexical-velt-comments';

const cleanState = exportJSONWithoutComments(editor);
```
