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

# Monaco Setup

> Add Velt text comments to a Monaco editor with the Velt Monaco comments package.

![Add text comments in an editor](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/Add-Text-Comments.gif?s=1da499b73486c2acd4667b517baab389)

The Monaco integration renders comment highlights as view-only overlay elements positioned over the commented text. It does not modify your Monaco model, undo history, or saved source code.

## Setup

#### Step 1: Add Comment components

* Add the `Velt Comments` component to the root of your app. This component is required to create and render comments in your app.
* Authenticate the user with `authProvider` and set the Velt document before users add comments.
* Set the `textMode` prop to `false` to hide the default Velt text comment tool. Monaco selections are handled by `@veltdev/monaco-velt-comments`.
* Add `VeltCommentsSidebar` if you want a Google Docs-style comment sidebar.

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { VeltComments, VeltCommentsSidebar, VeltProvider, useSetDocument } from '@veltdev/react';
>
> const user = {
>   userId: 'user-1',
>   organizationId: 'org-1',
>   name: 'User One',
>   email: 'user@example.com',
> };
>
> function VeltSetup() {
>   useSetDocument('document-id', { documentName: 'Document name' });
>   return null;
> }
>
> function App() {
>   return (
>     <VeltProvider apiKey="API_KEY" authProvider={{ user }}>
>       <VeltSetup />
>       <VeltComments textMode={false} />
>       <VeltCommentsSidebar />
>       {/* Your app content */}
>     </VeltProvider>
>   );
> }
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <body>
>   <velt-comments text-mode="false"></velt-comments>
> </body>
> ```

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

> [tab] React / Next.js
>
> ```bash theme={null}
> npm i @veltdev/monaco-velt-comments monaco-editor @monaco-editor/react
> ```

> [tab] Other Frameworks
>
> ```bash theme={null}
> npm i @veltdev/monaco-velt-comments monaco-editor @veltdev/client
> ```

`monaco-editor` is a peer dependency and must be provided by your Monaco app. The package uses the Monaco editor instance your app creates and does not bundle Monaco at runtime.

#### Step 3: Register the Monaco editor with Velt Comments

Register the integration on the Monaco editor instance returned by `monaco.editor.create` or by `@monaco-editor/react`'s `onMount`. Keep the returned handle so you can dispose it on teardown.

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { useEffect, useRef, useState } from 'react';
> import { Editor as MonacoReact, loader } from '@monaco-editor/react';
> import { useCommentAnnotations } from '@veltdev/react';
> import * as monaco from 'monaco-editor';
> import {
>   registerVeltComments,
>   renderComments,
>   type MonacoEditor,
>   type VeltCommentsHandle,
> } from '@veltdev/monaco-velt-comments';
>
> loader.config({ monaco });
>
> const EDITOR_ID = 'my-editor';
>
> function MonacoTextEditor() {
>   const [editor, setEditor] = useState<MonacoEditor | null>(null);
>   const handleRef = useRef<VeltCommentsHandle | null>(null);
>   const commentAnnotations = useCommentAnnotations();
>
>   useEffect(() => {
>     if (!editor) return;
>
>     renderComments({
>       editor,
>       editorId: EDITOR_ID,
>       commentAnnotations: commentAnnotations ?? [],
>     });
>   }, [editor, commentAnnotations]);
>
>   useEffect(() => {
>     return () => handleRef.current?.dispose();
>   }, []);
>
>   return (
>     <MonacoReact
>       height="480px"
>       defaultLanguage="typescript"
>       defaultValue={'const greeting = "hello world";\n'}
>       options={{ automaticLayout: true, wordWrap: 'on' }}
>       onMount={(mountedEditor) => {
>         setEditor(mountedEditor);
>         handleRef.current = registerVeltComments(mountedEditor, {
>           editorId: EDITOR_ID,
>         });
>       }}
>     />
>   );
> }
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import * as monaco from 'monaco-editor';
> import { registerVeltComments } from '@veltdev/monaco-velt-comments';
>
> const editor = monaco.editor.create(document.querySelector('#editor'), {
>   value: 'const greeting = "hello world";\n',
>   language: 'typescript',
>   automaticLayout: true,
>   wordWrap: 'on',
> });
>
> const handle = registerVeltComments(editor, {
>   editorId: 'my-editor',
> });
>
> // Later, for example during teardown:
> handle.dispose();
> ```

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

Add a button that users can click to add comments after selecting text in the Monaco editor.

**Important:** Use `onMouseDown` with `preventDefault()` so the browser does not move focus away from Monaco before `addComment` reads the current selection. Keep the actual `addComment` call in `onClick`.

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { addComment } from '@veltdev/monaco-velt-comments';
>
> const handleAddComment = () => {
>   if (!editor) return;
>
>   void addComment({
>     editor,
>     editorId: EDITOR_ID,
>   });
> };
>
> <button
>   onMouseDown={(event) => event.preventDefault()}
>   onClick={handleAddComment}
> >
>   Add Comment
> </button>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <button id="add-comment">Add Comment</button>
> <div id="editor"></div>
> ```
>
> ```ts theme={null}
> import { addComment } from '@veltdev/monaco-velt-comments';
>
> const addCommentButton = document.querySelector('#add-comment');
>
> addCommentButton.addEventListener('mousedown', (event) => {
>   event.preventDefault();
> });
>
> addCommentButton.addEventListener('click', () => {
>   void addComment({ editor, editorId: 'my-editor' });
> });
> ```

Registering the integration also adds an **Add Comment** Monaco editor action in the command palette and right-click menu. The action is enabled only when there is a non-empty editor selection.

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

* Call this method to add a comment to selected text in the Monaco editor.
* Params: [`AddCommentRequest`](https://velt.dev/docs/api-reference/sdk/models/data-models#addcommentrequest-10). It has the following properties:
  * `editor`: Monaco `IStandaloneCodeEditor` instance.
  * `editorId`: Id of the editor. Use this if you have multiple Monaco editors on the same page. (optional)
  * `context`: Add custom metadata to the Comment Annotation. [Learn more](https://velt.dev/docs/async-collaboration/comments/customize-behavior.md#metadata). (optional)

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { addComment } from '@veltdev/monaco-velt-comments';
>
> const addCommentRequest = {
>   editor,
>   editorId: 'EDITOR_ID',
>   context: {
>     fileId: 'file-123',
>     language: 'typescript',
>   },
> };
>
> void addComment(addCommentRequest);
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import { addComment } from '@veltdev/monaco-velt-comments';
>
> const addCommentRequest = {
>   editor,
>   editorId: 'EDITOR_ID',
>   context: {
>     fileId: 'file-123',
>     language: 'typescript',
>   },
> };
>
> void addComment(addCommentRequest);
> ```

The library automatically writes `context.textEditorConfig` with the selected text, its 1-based occurrence index in the document, and the editor ID when one is provided.

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

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

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { useEffect } from 'react';
> import { useCommentAnnotations } from '@veltdev/react';
> import { renderComments } from '@veltdev/monaco-velt-comments';
>
> const commentAnnotations = useCommentAnnotations();
>
> useEffect(() => {
>   if (!editor) return;
>
>   renderComments({
>     editor,
>     editorId: 'EDITOR_ID',
>     commentAnnotations: commentAnnotations ?? [],
>   });
> }, [editor, commentAnnotations]);
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import { renderComments } from '@veltdev/monaco-velt-comments';
>
> const commentElement = Velt.getCommentElement();
> commentElement.getAllCommentAnnotations().subscribe((annotations) => {
>   renderComments({
>     editor,
>     editorId: 'EDITOR_ID',
>     commentAnnotations: annotations,
>   });
> });
> ```

#### Step 7: Re-apply Monaco comment highlights (optional)

* Monaco renders comment highlights as view-only overlay elements.
* The integration does not write Velt comment marks into your Monaco model or saved source code.
* Save your Monaco model value normally. After you call `model.setValue(...)`, `editor.setModel(...)`, or load saved content, call `renderComments` again.

```ts theme={null}
const value = editor.getValue();
// Save value to your backend.

renderComments({
  editor,
  editorId: 'EDITOR_ID',
  commentAnnotations,
});
```

#### Step 8: Style the commented text

* You can style the commented text by adding CSS for the `velt-comment-text` element.
* Monaco highlights are rendered as overlay elements in the outer document, so broad `velt-comment-text` styles are appropriate for this integration.

```css theme={null}
velt-comment-text {
  background-color: rgba(255, 212, 0, 0.4);
  border-bottom: 2px solid #ffd400;
  cursor: pointer;
}

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

### Multiple Monaco editors

When using multiple Monaco editors on the same page, provide unique `editorId` values. The library stores `editorId` in `context.textEditorConfig.editorId` and filters annotations by that value when rendering.

```tsx theme={null}
const editor1Handle = registerVeltComments(editor1, { editorId: 'editor-1' });
const editor2Handle = registerVeltComments(editor2, { editorId: 'editor-2' });

await addComment({
  editor: editor1,
  editorId: 'editor-1',
});

renderComments({
  editor: editor2,
  editorId: 'editor-2',
  commentAnnotations,
});

editor1Handle.dispose();
editor2Handle.dispose();
```

### TypeScript support

The package includes full TypeScript definitions.

```ts theme={null}
import type {
  AddCommentRequest,
  AnchorEntry,
  CommentAnnotation,
  CommentAnnotationContext,
  MonacoEditor,
  MonacoVeltCommentsConfig,
  RenderCommentsRequest,
  SelectionContext,
  SyncAnchor,
  VeltCommentsHandle,
} from '@veltdev/monaco-velt-comments';
```

## Complete Example

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { useCallback, useEffect, useRef, useState } from 'react';
> import { Editor as MonacoReact, loader } from '@monaco-editor/react';
> import {
>   VeltComments,
>   VeltCommentsSidebar,
>   VeltCommentsSidebarButton,
>   VeltPresence,
>   VeltProvider,
>   useCommentAnnotations,
>   useSetDocument,
> } from '@veltdev/react';
> import * as monaco from 'monaco-editor';
> import {
>   addComment,
>   registerVeltComments,
>   renderComments,
>   type MonacoEditor,
>   type VeltCommentsHandle,
> } from '@veltdev/monaco-velt-comments';
>
> loader.config({ monaco });
>
> const EDITOR_ID = 'main-editor';
>
> function InitializeDocument() {
>   useSetDocument('monaco-comments-doc', {
>     documentName: 'Monaco Comments Document',
>   });
>
>   return null;
> }
>
> function MyEditor() {
>   const [editor, setEditor] = useState<MonacoEditor | null>(null);
>   const handleRef = useRef<VeltCommentsHandle | null>(null);
>   const commentAnnotations = useCommentAnnotations();
>
>   useEffect(() => {
>     if (!editor) return;
>
>     renderComments({
>       editor,
>       editorId: EDITOR_ID,
>       commentAnnotations: commentAnnotations ?? [],
>     });
>   }, [editor, commentAnnotations]);
>
>   useEffect(() => {
>     return () => handleRef.current?.dispose();
>   }, []);
>
>   const handleAddComment = useCallback(() => {
>     if (!editor) return;
>
>     void addComment({
>       editor,
>       editorId: EDITOR_ID,
>       context: { source: 'monaco-editor' },
>     });
>   }, [editor]);
>
>   return (
>     <div>
>       <div>
>         <VeltPresence />
>         <VeltCommentsSidebarButton />
>         <button
>           onMouseDown={(event) => event.preventDefault()}
>           onClick={handleAddComment}
>         >
>           Add Comment
>         </button>
>       </div>
>
>       <MonacoReact
>         height="480px"
>         defaultLanguage="typescript"
>         defaultValue={'const greeting = "hello world";\n'}
>         options={{
>           automaticLayout: true,
>           wordWrap: 'on',
>           scrollBeyondLastLine: false,
>         }}
>         onMount={(mountedEditor) => {
>           setEditor(mountedEditor);
>           handleRef.current = registerVeltComments(mountedEditor, {
>             editorId: EDITOR_ID,
>           });
>         }}
>       />
>     </div>
>   );
> }
>
> const user = {
>   userId: 'user-1',
>   organizationId: 'org-1',
>   name: 'User One',
>   email: 'user@example.com',
> };
>
> export default function App() {
>   return (
>     <VeltProvider apiKey="API_KEY" authProvider={{ user }}>
>       <InitializeDocument />
>       <VeltComments textMode={false} />
>       <MyEditor />
>       <VeltCommentsSidebar />
>     </VeltProvider>
>   );
> }
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import { initVelt } from '@veltdev/client';
> import * as monaco from 'monaco-editor';
> import {
>   addComment,
>   registerVeltComments,
>   renderComments,
> } from '@veltdev/monaco-velt-comments';
>
> const client = await initVelt('API_KEY');
> await client.identify({
>   userId: 'user-1',
>   organizationId: 'org-1',
>   name: 'User One',
>   email: 'user@example.com',
> });
>
> client.setDocument('monaco-comments-doc', {
>   documentName: 'Monaco Comments Document',
> });
>
> const editor = monaco.editor.create(document.querySelector('#editor'), {
>   value: 'const greeting = "hello world";\n',
>   language: 'typescript',
>   automaticLayout: true,
>   wordWrap: 'on',
> });
>
> const editorId = 'main-editor';
> const handle = registerVeltComments(editor, { editorId });
> const commentElement = Velt.getCommentElement();
>
> commentElement.getAllCommentAnnotations().subscribe((commentAnnotations) => {
>   renderComments({
>     editor,
>     editorId,
>     commentAnnotations,
>   });
> });
>
> const addCommentButton = document.querySelector('#add-comment');
> addCommentButton.addEventListener('mousedown', (event) => {
>   event.preventDefault();
> });
> addCommentButton.addEventListener('click', () => {
>   void addComment({ editor, editorId });
> });
>
> window.addEventListener('beforeunload', () => {
>   handle.dispose();
>   editor.dispose();
> });
> ```

## APIs

#### [registerVeltComments()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#registerveltcomments)

Registers the Velt comments integration on a Monaco editor instance. The call is idempotent per editor and returns a handle that tears down editor listeners, tracking decorations, overlay elements, renderer state, and local selected-comment subscriber cleanup.

* Params:
  * `editor`: Monaco `IStandaloneCodeEditor` instance.
  * `config`: [`MonacoVeltCommentsConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#monacoveltcommentsconfig). (optional)
* Returns: [`VeltCommentsHandle`](https://velt.dev/docs/api-reference/sdk/models/data-models#veltcommentshandle)

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { registerVeltComments } from '@veltdev/monaco-velt-comments';
>
> const handle = registerVeltComments(editor, {
>   editorId: 'my-editor',
> });
>
> handle.dispose();
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import { registerVeltComments } from '@veltdev/monaco-velt-comments';
>
> const handle = registerVeltComments(editor, {
>   editorId: 'my-editor',
> });
>
> handle.dispose();
> ```

#### [addComment()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#addcomment-11)

Creates a Velt comment annotation for the currently selected Monaco text. The selected text and its occurrence index are stored in `annotation.context.textEditorConfig`; the document content is not modified.

* Params: [`AddCommentRequest`](https://velt.dev/docs/api-reference/sdk/models/data-models#addcommentrequest-10)
* Returns: `Promise<void>`

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { addComment } from '@veltdev/monaco-velt-comments';
>
> await addComment({
>   editor,
>   editorId: 'my-editor',
>   context: {
>     fileId: 'file-123',
>     language: 'typescript',
>   },
> });
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import { addComment } from '@veltdev/monaco-velt-comments';
>
> await addComment({
>   editor,
>   editorId: 'my-editor',
>   context: {
>     fileId: 'file-123',
>     language: 'typescript',
>   },
> });
> ```

#### [renderComments()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#rendercomments-11)

Resolves Velt comment annotations to Monaco ranges and renders them as stable `<velt-comment-text>` overlay elements positioned over the commented text.

* Params: [`RenderCommentsRequest`](https://velt.dev/docs/api-reference/sdk/models/data-models#rendercommentsrequest-10)
* Returns: `void`

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { renderComments } from '@veltdev/monaco-velt-comments';
>
> renderComments({
>   editor,
>   editorId: 'my-editor',
>   commentAnnotations: commentAnnotations ?? [],
> });
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import { renderComments } from '@veltdev/monaco-velt-comments';
>
> renderComments({
>   editor,
>   editorId: 'my-editor',
>   commentAnnotations,
> });
> ```

#### [isVeltAvailable()](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#isveltavailable)

Checks whether the Velt SDK is loaded on `window.Velt`.

* Params: none
* Returns: `boolean`

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { isVeltAvailable, renderComments } from '@veltdev/monaco-velt-comments';
>
> if (isVeltAvailable()) {
>   renderComments({ editor, editorId: 'my-editor', commentAnnotations });
> }
> ```

> [tab] Other Frameworks
>
> ```ts theme={null}
> import { isVeltAvailable, renderComments } from '@veltdev/monaco-velt-comments';
>
> if (isVeltAvailable()) {
>   renderComments({ editor, editorId: 'my-editor', commentAnnotations });
> }
> ```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.