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

# Customize Behavior

# Filtering

The V2 sidebar exposes its filter, sort, group, and search behavior declaratively through inputs. Filters and sorts are described as data; the sidebar renders the matching surfaces and applies the selections client-side via [`applyCommentSidebarClientFilters()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#applycommentsidebarclientfilters).

There are three filter surfaces, each driven by its own input:

* **`filters`** — the Main Filter bottom-sheet/menu surface.
* **`miniFilters`** — a single header funnel dropdown.
* **`minimalFilters`** — multiple header dropdowns. When present, these replace the single funnel dropdown.

#### filters

* Define the Main Filter panel sections.
* Pass an array of [`FilterField`](https://velt.dev/docs/api-reference/sdk/models/data-models#filterfield) to define sections. Built-in fields are referenced by `field` id; custom fields use `valuePath`.
* When passed a [`CommentSidebarFilters`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentsidebarfilters) object (e.g. `{ status: ['OPEN'] }`) instead of `FilterField[]`, it is treated as active filter selections. Included keys replace their current selections, omitted keys are preserved, and **Reset** clears all selections. A present-but-empty array clears just that field; an empty object `{}` clears all selections.

Default: `[]`

> [tab] React / Next.js
>
> ```jsx theme={null}
> const filters = [
>   { field: 'status' },
>   { field: 'assigned' },
>   { field: 'authorName', label: 'Written By', valuePath: 'from.name' },
> ];
>
> <VeltCommentsSidebarV2 filters={filters} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2></velt-comments-sidebar-v2>
> <script>
>   const sidebar = document.querySelector('velt-comments-sidebar-v2');
>   sidebar.filters = [
>     { field: 'status' },
>     { field: 'assigned' },
>     { field: 'authorName', label: 'Written By', valuePath: 'from.name' },
>   ];
> </script>
> ```

**Active-selections object form** — pass a [`CommentSidebarFilters`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentsidebarfilters) object instead of a `FilterField[]` to apply active filter selections. The values render as checked options in the filter panel and are cleared by **Reset**:

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2
>   filters={{
>     status: ['OPEN'],
>     people: [{ userId: '1.1' }, { userId: '2.3' }],
>   }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2></velt-comments-sidebar-v2>
> <script>
>   const sidebar = document.querySelector('velt-comments-sidebar-v2');
>   sidebar.filters = {
>     status: ['OPEN'],
>     people: [{ userId: '1.1' }, { userId: '2.3' }],
>   };
> </script>
> ```

#### default status selection

On first load, the Status field starts with **Open** and every **In Progress** status selected, so the sidebar shows active comments by default. These selections appear as checked options in the Main Filter panel, and users can clear them like any other filter.

The sidebar skips this default selection when:

* Filter state was restored from `sessionStorage`.
* You supplied a status selection through [`setCommentSidebarFilters()`](#setcommentsidebarfilters).
* The user has already changed the Status selection.

> [!NOTE]
>
> If the status catalog loads after the sidebar renders and the user hasn't touched the Status field, the default selection refreshes to match the catalog's current Open and In Progress statuses.

To show resolved and terminal comments, select **All**, clear the Status field, or use **Reset**. Clearing other fields doesn't affect resolved-comment visibility, and Reset doesn't re-apply the default statuses.

#### priority "Not set" option

The default Priority field includes a **Not set** option for comments without a priority. A custom [`FilterField`](https://velt.dev/docs/api-reference/sdk/models/data-models#filterfield) with `includeUnset: false` omits this option.

#### setCommentSidebarFilters

Use `setCommentSidebarFilters()` to apply client-provided values as selected options in the sidebar. Each call replaces selections for keys it includes and preserves omitted keys:

* Pass an empty array to clear one field.
* Pass an empty object (`{}`) to clear every selected field.
* Use **Reset** in the Main Filter panel to clear client-provided selections.

Facet counts remain absolute within the page-scoped annotation set instead of shrinking around the client-provided selections. The Main Filter badge includes these selections. A non-empty selection also filters when its field is not displayed in the panel; empty undeclared fields are ignored, and declared fields are not duplicated.

Values are normalized as follows:

* `location`: by `id`, falling back to `locationName`
* `people`, `assigned`, `tagged`, and `involved`: by `userId`, falling back to `email`
* `status`, `priority`, and `category`: by the provided values without normalization
* `accessModes`: by comment visibility (`'public'` or `'private'`)
* `version`: by `id`
* Custom fields: string values or objects containing `id` and `name`

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { useVeltClient } from '@veltdev/react';
>
> const { client } = useVeltClient();
> const commentElement = client.getCommentElement();
>
> commentElement.setCommentSidebarFilters({
>   status: ['OPEN'],
>   involved: [{ userId: 'user-123' }],
>   location: [{ locationName: 'Home' }],
> });
>
> commentElement.setCommentSidebarFilters({ location: [] }); // Clear one field
> commentElement.setCommentSidebarFilters({}); // Clear all fields
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> commentElement.setCommentSidebarFilters({
>   status: ['OPEN'],
>   involved: [{ userId: 'user-123' }],
>   location: [{ locationName: 'Home' }],
> });
>
> commentElement.setCommentSidebarFilters({ location: [] }); // Clear one field
> commentElement.setCommentSidebarFilters({}); // Clear all fields
> ```

#### location identity

The sidebar identifies a location by its `id`, falling back to `locationName` when the id is `null`, `undefined`, or an empty string. An id of `0` remains valid, numeric annotation ids compare with equivalent string filter values, and `id` takes precedence when both fields are present.

This identity is used consistently by grouping, location filter options and matching, page mode, and client filters. Comments without any location context appear in the **Others** group.

#### people filter identity

People, Involved, Assigned, and Tagged options are keyed by `userId` and use the person's name as the label, with an email fallback. Records containing only an email do not create filter options, preventing duplicate options when another record for the same person contains a `userId`.

#### miniFilters

* Render a single header funnel dropdown with one section per field.

Default: `[]`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 miniFilters={[{ field: 'status' }, { field: 'priority' }, { field: 'involved' }]} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2></velt-comments-sidebar-v2>
> <script>
>   const sidebar = document.querySelector('velt-comments-sidebar-v2');
>   sidebar['mini-filters'] = [{ field: 'status' }, { field: 'priority' }, { field: 'involved' }];
> </script>
> ```

#### minimalFilters

* Renders one or more dropdowns in the sidebar header (these replace the single `miniFilters` funnel when present).
* Each entry in the array creates **one dropdown**. The entry's `type` decides what that dropdown contains, and the matching input (`fields`, `sorts`, or `actions`) provides its content.

Default: `[]`

##### Filter-dropdown `type` scoping

| `type` | The dropdown shows | Built from |
| - | - | - |
| `filter` | Category checkbox sections (e.g. status, priority, assignee) | `fields` |
| `sort` | Single-select sort options (e.g. by date or unread) | `sorts` |
| `quick` | One-click filters (presets and/or path predicates) | `actions` |
| `actions` | A combined menu: a sort group and a quick group separated by a divider | `sorts` + `actions` |
| *(unset)* | Default quick presets plus any configured sections | — |

A **path predicate** is a rule that keeps only comments whose value at a given field path matches. For example, `{ path: 'from.userId', value: '1.1' }` keeps comments authored by the user with id `1.1`. The `value` is a literal (there is no `@me` token), and paths auto-flatten nested arrays (e.g. `comments.taggedUserContacts.contact.userId`).

Each dropdown is rendered by the filter-dropdown primitive (`VeltCommentSidebarV2FilterDropdown` / `velt-comment-sidebar-filter-dropdown-v2`). See [`Primitive components`](https://velt.dev/docs/ui-customization/reference/primitives) for the current primitive list.

The examples below show one dropdown per `type`.

**`filter` — category checkboxes** (built from `fields`):

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 minimalFilters={[{ type: 'filter', fields: [{ field: 'status' }, { field: 'priority' }] }]} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 minimal-filters='[{"type":"filter","fields":[{"field":"status"},{"field":"priority"}]}]'></velt-comments-sidebar-v2>
> ```

**`sort` — sort options** (built from `sorts`):

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 minimalFilters={[{ type: 'sort', sorts: ['date', 'unread'] }]} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 minimal-filters='[{"type":"sort","sorts":["date","unread"]}]'></velt-comments-sidebar-v2>
> ```

**`quick` — one-click filters** (built from `actions` — presets and/or path predicates):

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2
>   minimalFilters={[
>     { type: 'quick', actions: ['open', 'resolved', { label: 'Written By Me', path: 'from.userId', value: '1.1' }] },
>   ]}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 minimal-filters='[{"type":"quick","actions":["open","resolved",{"label":"Written By Me","path":"from.userId","value":"1.1"}]}]'></velt-comments-sidebar-v2>
> ```

To match several paths in one quick filter, give an action a list of `conditions` plus an `operator`:

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2
>   minimalFilters={[
>     {
>       type: 'quick',
>       actions: [{
>         label: 'Involved',
>         operator: 'or',
>         conditions: [
>           { path: 'from.userId', value: '1.1' },
>           { path: 'assignedTo.userId', value: '1.1' },
>           { path: 'comments.taggedUserContacts.contact.userId', value: '1.1' },
>         ],
>       }],
>     },
>   ]}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2
>   minimal-filters='[{"type":"quick","actions":[{"label":"Involved","operator":"or","conditions":[{"path":"from.userId","value":"1.1"},{"path":"assignedTo.userId","value":"1.1"},{"path":"comments.taggedUserContacts.contact.userId","value":"1.1"}]}]}]'>
> </velt-comments-sidebar-v2>
> ```

**`actions` — combined sort + quick menu** (built from `sorts` + `actions`, separated by a divider):

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2
>   minimalFilters={[
>     {
>       type: 'actions',
>       sorts: ['date', 'unread'],
>       actions: [
>         { preset: 'resolved', label: 'Show resolved comments' },
>         { label: 'Only your mentions', path: 'comments.taggedUserContacts.contact.userId', value: '1.1' },
>       ],
>     },
>   ]}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2
>   minimal-filters='[{"type":"actions","sorts":["date","unread"],"actions":[{"preset":"resolved","label":"Show resolved comments"},{"label":"Only your mentions","path":"comments.taggedUserContacts.contact.userId","value":"1.1"}]}]'>
> </velt-comments-sidebar-v2>
> ```

**Combine multiple dropdowns** — pass several entries to render them side by side:

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2
>   minimalFilters={[
>     { type: 'filter', fields: [{ field: 'status' }] },
>     { type: 'sort', sorts: ['date', 'unread'] },
>     { type: 'quick', actions: ['open', 'resolved'] },
>   ]}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 minimal-filters='[{"type":"filter","fields":[{"field":"status"}]},{"type":"sort","sorts":["date","unread"]},{"type":"quick","actions":["open","resolved"]}]'></velt-comments-sidebar-v2>
> ```

> [!NOTE]
>
> Prefer configuring dropdowns through `minimalFilters` as shown above. If you need to place or restyle a dropdown directly in your own markup, you can set these same inputs on the filter-dropdown primitive — see [`Primitives`](https://velt.dev/docs/ui-customization/primitives) and [`Primitive components`](https://velt.dev/docs/ui-customization/reference/primitives).

#### defaultMinimalFilter

* Set the default active quick filter applied on load (one of the `minimalFilters` quick presets).
* Type: `'all' | 'read' | 'unread' | 'resolved' | 'open' | 'assignedToMe' | 'reset'`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 defaultMinimalFilter="open" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 default-minimal-filter="open"></velt-comments-sidebar-v2>
> ```

> [!NOTE]
>
> The `all`, `unread`, `read`, `open`, and `assignedToMe` presets hide terminal statuses, such as Resolved, by default. If you explicitly select a terminal status in a status field filter, that selection overrides the preset and the matching comments appear.

#### filterOperator

* Control how active selections across different filter sections combine.
* Options: `and` or `or`
* This directly configures the Comment Sidebar V2 filter engine. The shared `systemFiltersOperator` input and API update the same effective operator.

Default: `and`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 filterOperator="or" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 filter-operator="or"></velt-comments-sidebar-v2>
> ```

#### filterPanelLayout

* Change the layout of the Main Filter panel.
* Options: `bottomSheet` or `menu`

Default: `bottomSheet`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 filterPanelLayout="menu" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 filter-panel-layout="menu"></velt-comments-sidebar-v2>
> ```

#### filterOptionLayout

* Change how options render within a filter section.
* Options: `dropdown` or `checkbox`

Default: `dropdown`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 filterOptionLayout="checkbox" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 filter-option-layout="checkbox"></velt-comments-sidebar-v2>
> ```

#### filterCount

* Show per-option facet counts. Counts remain absolute within the current page-scoped annotation set and do not shrink around selections supplied through `setCommentSidebarFilters()`. Disabling improves performance.

Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 filterCount={false} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 filter-count="false"></velt-comments-sidebar-v2>
> ```

#### systemFiltersOperator

* Specify whether different filter fields are combined with an `and` or `or` operator in the sidebar filter engine. Values within a single field always match with OR.
* Applies to client filters set via [`setCommentSidebarFilters()`](#setcommentsidebarfilters) as well, including a value set before the sidebar initializes and changes made at runtime.
* An explicit `filterOperator` set during initialization is preserved instead of being overwritten by the shared operator's initial default value.

Default: `and`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 systemFiltersOperator="or" />
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setSystemFiltersOperator('or');
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 system-filters-operator="or"></velt-comments-sidebar-v2>
> ```
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setSystemFiltersOperator('or');
> ```

#### filterGhostCommentsInSidebar

* Filter out and hide ghost comments from the sidebar.

Default: `false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 filterGhostCommentsInSidebar={true} />
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableFilterGhostCommentsInSidebar();
> commentElement.disableFilterGhostCommentsInSidebar();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 filter-ghost-comments-in-sidebar="true"></velt-comments-sidebar-v2>
> ```

#### excludeLocationIds

* Filter out comments from certain locations. These comments are not displayed in the sidebar.

Default: `[]`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 excludeLocationIds={['location1', 'location2']} />
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> commentElement.excludeLocationIdsFromSidebar(['location1', 'location2']);
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 exclude-location-ids='["location1", "location2"]'></velt-comments-sidebar-v2>
> ```

#### customActions

* Enable custom actions in the sidebar so you can add your own wireframe-driven controls.

Default: `false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 customActions={true} />
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableSidebarCustomActions();
> commentElement.disableSidebarCustomActions();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 custom-actions="true"></velt-comments-sidebar-v2>
> ```

#### applyCommentSidebarClientFilters

* Apply client-provided `CommentSidebarFilters` to a set of annotations, honoring the current `systemFiltersOperator`.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> const filtered = commentElement.applyCommentSidebarClientFilters(annotations, filters);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> const filtered = commentElement.applyCommentSidebarClientFilters(annotations, filters);
> ```

# Sorting

#### sortBy

* Set the default sort field. This sets the default sort, it does not render a sort dropdown.
* Type: [`SortBy`](https://velt.dev/docs/api-reference/sdk/models/data-models#sortby) — a built-in preset (e.g. `'date'`, `'unread'`) or a custom field key / dot-path (e.g. `'comments.createdAt'`).

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 sortBy="comments.createdAt" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 sort-by="comments.createdAt"></velt-comments-sidebar-v2>
> ```

#### sortOrder

* Set the default sort direction.
* Type: [`SortOrder`](https://velt.dev/docs/api-reference/sdk/models/data-models#sortorder) (`'asc' | 'desc'`)

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 sortOrder="desc" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 sort-order="desc"></velt-comments-sidebar-v2>
> ```

# Grouping

#### groupConfig

* Configure grouping in the sidebar. Grouping defaults to by-location when enabled.
* For location grouping, the current and additional-location groups start expanded while other location groups start collapsed. For document grouping, the current document starts expanded while other documents start collapsed.
* Status, priority, and custom-field groups start expanded.
* Explicit user expansion takes precedence over explicit collapse, which takes precedence over the grouping default. Both overrides persist in `sessionStorage`.
* A real location change resets the overrides so the new current group expands. The initial location emitted during a reload preserves restored overrides.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 groupConfig={{ enable: true, groupBy: 'location' }} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2></velt-comments-sidebar-v2>
> <script>
>   const sidebar = document.querySelector('velt-comments-sidebar-v2');
>   sidebar.setAttribute('group-config', JSON.stringify({ enable: true, groupBy: 'location' }));
> </script>
> ```

# Navigation

#### commentClick

* Subscribe to the `commentClick` event to listen for click events on comments in the sidebar list, to trigger actions like navigation.
* Payload is [`CommentClickEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentclickevent), which exposes the clicked `annotation`, `documentId`, `location`, `targetElementId`, and `context`.

> [tab] React / Next.js
>
> ```jsx theme={null}
> import { useCommentEventCallback } from '@veltdev/react';
> import { useEffect } from 'react';
>
> const commentClick = useCommentEventCallback('commentClick');
> useEffect(() => {
>   if (commentClick) {
>     console.log(commentClick.annotation, commentClick.documentId, commentClick.targetElementId);
>     const pageId = commentClick.location?.pageId;
>     if (pageId) {
>       yourNavigateToPageMethod(pageId);
>     }
>   }
> }, [commentClick]);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.on('commentClick').subscribe((event) => {
>   console.log(event?.annotation, event?.documentId, event?.targetElementId);
>   const pageId = event?.location?.pageId;
>   if (pageId) {
>     yourNavigateToPageMethod(pageId);
>   }
> });
> ```

#### commentNavigationButtonClick

* Subscribe to the `commentNavigationButtonClick` event, triggered when the navigation ("go to") button on a sidebar comment is clicked.
* Use this event to implement custom navigation logic. Payload is [`CommentNavigationButtonClickEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentnavigationbuttonclickevent), which exposes the same fields as [`CommentClickEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentclickevent) (`annotation`, `documentId`, `location`, `targetElementId`, `context`).

> [tab] React / Next.js
>
> ```jsx theme={null}
> import { useCommentEventCallback } from '@veltdev/react';
> import { useEffect } from 'react';
>
> const commentNav = useCommentEventCallback('commentNavigationButtonClick');
> useEffect(() => {
>   if (commentNav) {
>     console.log(commentNav.annotation, commentNav.documentId, commentNav.targetElementId);
>     const pageId = commentNav.location?.pageId;
>     if (pageId) {
>       yourNavigateToPageMethod(pageId);
>     }
>   }
> }, [commentNav]);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.on('commentNavigationButtonClick').subscribe((event) => {
>   console.log(event?.annotation, event?.documentId, event?.targetElementId);
>   const pageId = event?.location?.pageId;
>   if (pageId) {
>     yourNavigateToPageMethod(pageId);
>   }
> });
> ```

#### urlNavigation

* Enable automatic URL navigation when clicking comments in the sidebar.
* By default, clicking a comment doesn't update the page URL where the comment was added.

Default: `false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 urlNavigation={true} />
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableSidebarUrlNavigation();
> commentElement.disableSidebarUrlNavigation();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 url-navigation="true"></velt-comments-sidebar-v2>
> ```

#### queryParamsComments

* Sync the selected comment to URL query params.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 queryParamsComments={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 query-params-comments="true"></velt-comments-sidebar-v2>
> ```

# UI

#### pageMode

* Adds a composer in the sidebar where users can add comments without attaching them to any specific element.
* The list is scoped using the current [location identity](#location-identity), so a location with only `locationName` behaves the same as an id-based location.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 pageMode={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 page-mode="true"></velt-comments-sidebar-v2>
> ```

#### focusedThreadMode

* When you click a comment in the sidebar, it opens the thread in an expanded view within the sidebar itself.
* Other threads and actions like filters and search are hidden behind a back button.
* Enabling this mode also adds a navigation button in the comment dialog.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 focusedThreadMode={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 focused-thread-mode="true"></velt-comments-sidebar-v2>
> ```

#### openAnnotationInFocusMode

* When enabled, opens the comment dialog in focus mode when `focusedThreadMode` is enabled and either the reply button is clicked or a comment is selected via `selectCommentByAnnotationId()`.
* Requires `focusedThreadMode` to be enabled.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 focusedThreadMode={true} openAnnotationInFocusMode={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 focused-thread-mode="true" open-annotation-in-focus-mode="true"></velt-comments-sidebar-v2>
> ```

#### readOnly

* Make comment dialogs in the sidebar read-only to prevent users from editing comments.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 readOnly={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 read-only="true"></velt-comments-sidebar-v2>
> ```

#### embedMode

* Add the sidebar inline within your component; it takes up the full width and height of its container.
* In embed mode, the sidebar does not have a close button. Implement your own open/close on the host component.
* The React prop is typed `boolean`. The `embed-mode` HTML attribute takes a string.

Default: not set

> [tab] React / Next.js
>
> ```jsx theme={null}
> <div className="sidebar-container">
>   <VeltCommentsSidebarV2 embedMode={true} />
> </div>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <div class="sidebar-container">
>   <velt-comments-sidebar-v2 embed-mode="true"></velt-comments-sidebar-v2>
> </div>
> ```

#### floatingMode

* Open the sidebar in an overlay panel that floats over the page content.
* If you use this mode, do not add the sidebar component to your app separately.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 floatingMode={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 floating-mode="true"></velt-comments-sidebar-v2>
> ```

#### position

* Change the side of the viewport the sidebar opens from.
* Options: `left` or `right`

Default: `right`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 position="left" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 position="left"></velt-comments-sidebar-v2>
> ```

#### variant

* Set the layout variant of the sidebar.

Default: `sidebar`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 variant="inline" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 variant="inline"></velt-comments-sidebar-v2>
> ```

#### dialogVariant

* Set the variant for the embedded comment dialog rendered in the list.

Default: `sidebar`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 dialogVariant="sidebar" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 dialog-variant="sidebar"></velt-comments-sidebar-v2>
> ```

#### focusedThreadDialogVariant

* Set the variant for the focused-thread dialog.

Default: `sidebar`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 focusedThreadDialogVariant="sidebar" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 focused-thread-dialog-variant="sidebar"></velt-comments-sidebar-v2>
> ```

#### pageModeComposerVariant

* Set the variant for the page-mode composer.

Default: `sidebar`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 pageModeComposerVariant="sidebar" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 page-mode-composer-variant="sidebar"></velt-comments-sidebar-v2>
> ```

#### forceClose

* Force the sidebar to close on outside click, even when opened programmatically via API.

Default: `true`

> [!NOTE]
>
> This does not affect embed mode sidebar.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 forceClose={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 force-close="true"></velt-comments-sidebar-v2>
> ```

#### fullScreen

* Add a fullscreen toggle button to the header. In fullscreen mode the sidebar expands to fill the viewport.
* Observe state changes with the component-level `onFullscreenClick` output or the [`fullscreenClick`](#fullscreenclick) event API.

Default: `false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 fullScreen={true} onFullscreenClick={(e) => console.log('fullscreen', e)} />
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableFullScreenInSidebar();
> commentElement.disableFullScreenInSidebar();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 full-screen="true"></velt-comments-sidebar-v2>
> <script>
>   const sidebar = document.querySelector('velt-comments-sidebar-v2');
>   sidebar.addEventListener('onFullscreenClick', (e) => console.log('fullscreen', e));
> </script>
> ```

#### fullExpanded

* Render the sidebar fully expanded.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 fullExpanded={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 full-expanded="true"></velt-comments-sidebar-v2>
> ```

#### shadowDom

* Render the sidebar body inside a shadow root for style isolation.
* Shadow-DOM isolation is enabled by default. Opt out by setting `shadow-dom="false"` or calling `disableSidebarShadowDOM()`.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 shadowDom={false} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 shadow-dom="false"></velt-comments-sidebar-v2>
> ```

#### currentLocationSuffix

* Adds a "(This page)" suffix to the group name when the current location matches the group's location.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 currentLocationSuffix={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 current-location-suffix="true"></velt-comments-sidebar-v2>
> ```

#### dialogSelection

* When disabled, clicking a comment in the sidebar triggers a click event instead of opening the dialog inline.

Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 dialogSelection={false} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 dialog-selection="false"></velt-comments-sidebar-v2>
> ```

#### expandOnSelection

* Control whether comment dialogs automatically expand when selected in the sidebar.

Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 expandOnSelection={false} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 expand-on-selection="false"></velt-comments-sidebar-v2>
> ```

#### searchPlaceholder

* Customize the placeholder text shown in the search input of the sidebar.

Default: `Search comments`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 searchPlaceholder="New placeholder" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 search-placeholder="New placeholder"></velt-comments-sidebar-v2>
> ```

#### commentPlaceholder

* Customize the placeholder text for the dialog composer (the comment input that appears in comment dialogs/threads).

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 commentPlaceholder="Add a comment..." />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 comment-placeholder="Add a comment..."></velt-comments-sidebar-v2>
> ```

#### replyPlaceholder

* Customize the placeholder text for reply input fields in the sidebar.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 replyPlaceholder="Write a reply..." />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 reply-placeholder="Write a reply..."></velt-comments-sidebar-v2>
> ```

#### pageModePlaceholder

* Customize the placeholder text for the page-mode composer.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 pageModePlaceholder="Add a page comment..." />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 page-mode-placeholder="Add a page comment..."></velt-comments-sidebar-v2>
> ```

#### editPlaceholder

* Customize the placeholder text shown when editing an existing comment or reply.
* Use `editCommentPlaceholder` for the first comment and `editReplyPlaceholder` for replies; both take precedence over `editPlaceholder`.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2
>   editPlaceholder="Edit..."
>   editCommentPlaceholder="Edit comment..."
>   editReplyPlaceholder="Edit reply..."
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2
>   edit-placeholder="Edit..."
>   edit-comment-placeholder="Edit comment..."
>   edit-reply-placeholder="Edit reply...">
> </velt-comments-sidebar-v2>
> ```

#### sidebarButtonCountType

* Change what the sidebar button count reflects.
  * `default`: total count of comments in open and in-progress states.
  * `filter`: count of the sidebar's filtered comments, including `0` for an empty result. The count updates when comments are deleted.
* When [`filterCommentsOnDom`](https://velt.dev/docs/async-collaboration/comments/customize-behavior#filtercommentsondom) is enabled, the same filtered list controls which pins appear on the page.
* The current filtered result is preserved while the sidebar is loading. It is cleared when the sidebar is destroyed so a removed sidebar no longer gates the badge or on-page pins.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 sidebarButtonCountType="filter" />
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setSidebarButtonCountType('filter');
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 sidebar-button-count-type="filter"></velt-comments-sidebar-v2>
> ```
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setSidebarButtonCountType('filter');
> ```

#### context

* Pass custom context data to page-mode composer comments in the sidebar. The provided context object is attached to any comment added via the page-mode composer.

Default: `null`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 context={{ jobId: 'job-page-mode', jobStatus: 'page comment' }} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentSidebarElement = document.querySelector('velt-comments-sidebar-v2');
> commentSidebarElement?.setAttribute('context', JSON.stringify({ jobId: 'job-page-mode', jobStatus: 'page comment' }));
> ```

#### Virtual scrolling

* The V2 list uses virtual scrolling. Tune it with `measuredSize` (estimated row size in px), `minBufferPx`, and `maxBufferPx`.
* Rows wider than the viewport are clipped to the sidebar width instead of creating a horizontal scrollbar.

Defaults: `measuredSize` = `220`, `minBufferPx` = `1000`, `maxBufferPx` = `2000`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentsSidebarV2 measuredSize={220} minBufferPx={1000} maxBufferPx={2000} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments-sidebar-v2 measured-size="220" min-buffer-px="1000" max-buffer-px="2000"></velt-comments-sidebar-v2>
> ```

# Events

#### sidebarOpen

* Subscribe to the `sidebarOpen` event, fired when the sidebar opens. Payload is [`SidebarOpenEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#sidebaropenevent).

> [tab] React / Next.js
>
> ```jsx theme={null}
> import { useCommentEventCallback } from '@veltdev/react';
> import { useEffect } from 'react';
>
> const sidebarOpen = useCommentEventCallback('sidebarOpen');
> useEffect(() => {
>   if (sidebarOpen) {
>     console.log('opened', sidebarOpen);
>   }
> }, [sidebarOpen]);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.on('sidebarOpen').subscribe((event) => {
>   console.log('opened', event);
> });
> ```

#### sidebarClose

* Subscribe to the `sidebarClose` event, fired when the sidebar closes. Payload is [`SidebarCloseEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#sidebarcloseevent).

> [tab] React / Next.js
>
> ```jsx theme={null}
> import { useCommentEventCallback } from '@veltdev/react';
> import { useEffect } from 'react';
>
> const sidebarClose = useCommentEventCallback('sidebarClose');
> useEffect(() => {
>   if (sidebarClose) {
>     console.log('closed', sidebarClose);
>   }
> }, [sidebarClose]);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.on('sidebarClose').subscribe((event) => {
>   console.log('closed', event);
> });
> ```

#### fullscreenClick

* Emitted when the fullscreen toggle in the sidebar header is clicked. Provides a [`FullscreenClickEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#fullscreenclickevent) whose `fullScreen` is the new state after the toggle.
* Use this event to react to fullscreen toggles through the standard event API, without wiring up the component-level `onFullscreenClick` output.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const fullscreenEvent = useCommentEventCallback('fullscreenClick');
> useEffect(() => {
>   if (fullscreenEvent) {
>     console.log(fullscreenEvent.fullScreen); // true = now fullscreen
>   }
> }, [fullscreenEvent]);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.on('fullscreenClick').subscribe((event) => {
>   console.log(event.fullScreen); // true = now fullscreen
> });
> ```

# Sidebar controls

#### openCommentSidebar / closeCommentSidebar / toggleCommentSidebar

* Programmatically open, close, or toggle the sidebar.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.openCommentSidebar();
> commentElement.closeCommentSidebar();
> commentElement.toggleCommentSidebar();
>
> // Open the sidebar on a specific thread
> commentElement.openCommentSidebar({ annotationId: 'ANNOTATION_ID' });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.openCommentSidebar();
> commentElement.closeCommentSidebar();
> commentElement.toggleCommentSidebar();
>
> // Open the sidebar on a specific thread
> commentElement.openCommentSidebar({ annotationId: 'ANNOTATION_ID' });
> ```

Pass `annotationId` to open the sidebar on a thread. With `focusedThreadMode` and `openAnnotationInFocusMode` on, the thread opens in focused view. Otherwise the sidebar scrolls to its card.

> [!NOTE]
>
> For V2 wireframe and primitive customization, start with the [`Component catalog`](https://velt.dev/docs/ui-customization/reference/component-catalog#sidebar-slot-trees), then use [`Wireframe components`](https://velt.dev/docs/ui-customization/reference/wireframe-components) for the complete slot tree and [`Primitive components`](https://velt.dev/docs/ui-customization/reference/primitives) for the primitive list. The sidebar is shadow-DOM isolated by default.


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