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

# Template Variables

> Look up the template variables available in each Velt component's wireframes, with usage examples.

Template variables are `{…}` tokens that read live Velt data inside a wireframe. Use them to **display** dynamic values, or as the condition for a [conditional template](https://velt.dev/docs/ui-customization/conditional-templates.md) or [conditional class](https://velt.dev/docs/ui-customization/conditional-classes.md).

Velt exposes its own data, and you can inject your own. Every available name is in the [catalog](#variable-catalog-per-component) at the end of this page.

## Display a variable

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Display user name
> <VeltData field="user.name" />
>
> // Access nested properties
> <VeltData field="userContact.organizationName" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-data field="user.name"></velt-data>
>
> <velt-data field="userContact.organizationName"></velt-data>
> ```

Object variables support nested paths like `{annotation.from.name}`; scalars don't. If a deep path comes back empty, check the variable's `type` in the catalog.

**Example: a custom user card**

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltAutocompleteOptionWireframe>
>   <div className="user-card">
>     <h3><VeltData field="userContact.name" /></h3>
>     <p><VeltData field="userContact.email" /></p>
>     <span className="org"><VeltData field="userContact.organizationName" /></span>
>   </div>
> </VeltAutocompleteOptionWireframe>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-autocomplete-option-wireframe>
>   <div class="user-card">
>     <h3><velt-data field="userContact.name"></velt-data></h3>
>     <p><velt-data field="userContact.email"></velt-data></p>
>     <span class="org"><velt-data field="userContact.organizationName"></velt-data></span>
>   </div>
> </velt-autocomplete-option-wireframe>
> ```

## The main data objects

A few variables are whole objects. The [catalog](#variable-catalog-per-component) tells you which are available where; these links give you every field each one carries:

| Variable | Available in | Fields |
| - | - | - |
| `user` | Everywhere | [User](https://velt.dev/docs/api-reference/sdk/models/data-models.md#user) |
| `userContact` | Autocomplete components | [User](https://velt.dev/docs/api-reference/sdk/models/data-models.md#user) |
| `commentAnnotation` | Comment components | [CommentAnnotation](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentannotation) |
| `comment` | Comment thread components | [Comment](https://velt.dev/docs/api-reference/sdk/models/data-models.md#comment) |
| `notification` | Notification components | [Notification](https://velt.dev/docs/api-reference/sdk/models/data-models.md#notification) |

Counts are plain numbers: `unreadCommentAnnotationCount` and `unreadCommentCount` anywhere, plus `filteredCommentAnnotationsCount` in the comments sidebar.

> [!WARNING]
>
> **`context` resolves two different ways.** `field="context.someProperty"` reads the **parent component's** local UI state (e.g. the Inline Comments Section's own `context`). To read context stored on the annotation, use `field="annotation.context.someProperty"`. See [Context](https://velt.dev/docs/ui-customization/context.md).

## Inject your own data

Push your app's data into Velt with `setUiState()`, then read it in any wireframe, condition, or class.

> [tab] React / Next.js
>
> ```jsx theme={null}
> client.setUiState({
>   projectName: 'Dashboard 2.0',
>   teamSize: 5,
>   customFlag: true
> });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> Velt.setUiState({
>   projectName: 'Dashboard 2.0',
>   teamSize: 5,
>   customFlag: true
> });
> ```

Read it back with the `uiState.` prefix, exactly like a built-in variable:

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentDialogWireframe.Header>
>   <div className="header">
>     <h2><VeltData field="uiState.projectName" /></h2>
>     <span>Team Size: <VeltData field="uiState.teamSize" /></span>
>   </div>
> </VeltCommentDialogWireframe.Header>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-dialog-header-wireframe>
>   <div class="header">
>     <h2><velt-data field="uiState.projectName"></velt-data></h2>
>     <span>Team Size: <velt-data field="uiState.teamSize"></velt-data></span>
>   </div>
> </velt-comment-dialog-header-wireframe>
> ```

`setUiState` is app-global. To attach data to **one comment**, use [Context](https://velt.dev/docs/ui-customization/context.md) instead.

## Which name form to use

Components read variables in one of two ways:

* **Short aliases** like `{annotation.from.name}`: Comment Dialog, Comments Sidebar, Comment Bubble, Inline Comments Section, Multi-Thread Comment Dialog, Text Comment, Notifications Panel, Notifications Tool, Activity Log. (These accept the explicit form below too.)
* **Explicit `{componentConfig.<name>}`**: Cursor, Presence, Huddle, Recording, Transcription, View Analytics, Area, Arrow, Tag, Reactions, Selection, Rewriter, Comments Tool, Sidebar Button, Autocomplete.

If a short alias resolves to `undefined`, fall back to `{componentConfig.<name>}`.

## Troubleshooting

A variable rendering blank or `undefined` is almost always one of these:

1. **Spelling.** Names are case-sensitive; copy them from the catalog.
2. **Scope.** You're in a slot that doesn't receive it (`{comment}` and `{commentIndex}` exist only inside thread-card descendants; `{notification}` only in the notifications panel).
3. **Name form.** Flat-config components need `{componentConfig.<name>}` (see above).
4. **Nesting.** The root isn't an object, so the deep path has nothing to resolve.

## Variable catalog (per component)

Every `{…}` variable you can read inside a wireframe, with an example for each.

* **Buckets:** `app` (per-user) · `data` (per-annotation) · `ui` (per-instance) · `feature` (SDK-config flags) · `iteration` (loop-scoped).
* **🔑** marks the boolean state flags you'll reach for most in `velt-if` / `velt-class`.
* **Iteration variables** appear inside list slots: `{i}` (alias `commentIndex`, 0-based), the per-item object (`option`, `filter`, `emoji`, `activity`, `dateGroup`, `chip`, `view`, `file`, …), and per-item booleans (`isSelected`, `isActive`, `isExpanded`, `isAscending`).
* **Function-typed variables** (`onClick…`, `initRecording`, `toggleSidebar`, `handleEmojiSelected`, …) are call-handlers you bind to events, not values to display.
* Examples work in both React and Other Frameworks; only the spelling differs (`veltIf` prop vs `velt-if` attribute, `<VeltData/>` vs `<velt-data>`).
* Need a deep field that isn't listed? `console.log` the object from a hook (e.g. `useCommentAnnotations()`) to see its exact shape.

### Comment Dialog

| name | type | bucket | meaning | example | 🔑 | | |
| - | - | - | - | - | - | - | - |
| `user` | object | app | current end-user (nested OK) | `veltIf="{user.userId} === {annotation.from.userId}"` | | | |
| `isUserAdmin` | bool | app | admin privileges | `veltIf="{isUserAdmin}"` | 🔑 | | |
| `isKnownUser` | bool | app | identified vs anonymous | `veltIf="!{isKnownUser}"` | 🔑 | | |
| `repliesUniqueUsers` | array | app | distinct reply authors | None | | | |
| `annotation` | object | data | the dialog's annotation | `<VeltData field="annotation.annotationNumber"/>` | | | |
| `annotation.status.id` / `.name` | string | data | status id / label | `veltIf="{annotation.status.id} === 'OPEN'"` | 🔑 | | |
| `annotation.priority.id` / `.name` | string | data | priority id / label | `veltClass="'urgent': {annotation.priority.id} === 'URGENT'"` | 🔑 | | |
| `annotation.from.userId` / `.name` | string | data | author | `<VeltData field="annotation.from.name"/>` | | | |
| `annotation.comments.length` | number | data | thread size | `<VeltData field="annotation.comments.length"/>` | | | |
| `annotation.assignedTo` | object | data | assignee (undefined = none) | `veltIf="!{annotation.assignedTo}"` | 🔑 | | |
| `annotation.resolvedByUser.name` | string | data | resolver name | `<VeltData field="annotation.resolvedByUser.name"/>` | | | |
| `annotation.context.<key>` | object | data | your attached [context](https://velt.dev/docs/ui-customization/context.md) | `<VeltData field="annotation.context.label"/>` | | | |
| `annotation.agent` | object | data | AI-agent author (present → agent suggestion card) | `veltIf="{annotation.agent}"` | 🔑 | | |
| `annotation.sourceType` | string | data | `'agent'` when agent-authored | `veltIf="{annotation.sourceType} === 'agent'"` | 🔑 | | |
| `annotation.type` / `annotation.commentType` | string | data | `'suggestion'` discriminator for agent suggestions | `veltIf="{annotation.type} === 'suggestion'"` | 🔑 | | |
| `annotation.suggestion.status` | string | data | resolved state (`'accepted'`/`'rejected'`; absent = pending) | `veltIf="{annotation.suggestion.status} === 'accepted'"` | 🔑 | | |
| `annotation.suggestion.resolvedBy.name` | string | data | who accepted/rejected the suggestion | `<VeltData field="annotation.suggestion.resolvedBy.name"/>` | | | |
| `annotation.suggestion.resolvedAt` | number | data | resolution timestamp | None | | | |
| `agentName` | string | data | agent display name (`annotation.agent.agentName`) | `<VeltData field="agentName"/>` | | | |
| `agentAvatar` | string | data | agent avatar URL (truthiness → has-avatar) | `veltIf="{agentAvatar}"` | 🔑 | | |
| `agentResultTitle` | string | data | agent result title (`annotation.agent.result.title`) | `<VeltData field="agentResultTitle"/>` | | | |
| `commentAnnotation` / `commentAnnotations` | object/array | data | aliases of annotation(s) | None | | | |
| `comment` / `commentObj` | object | data | per-comment (thread-card scope) | `<VeltData field="comment.from.name"/>` | | | |
| `annotations` / `allAnnotations` | array | data | in-scope / unfiltered | None | | | |
| `ghostComment` | object | data | annotation lost its DOM target | `veltIf="{ghostComment}"` | 🔑 | | |
| `editComment` / `editCommentIndex` | object/number | data | comment being edited / its index | `veltIf="{editCommentIndex} === {i}"` | | | |
| `assignTo` / `selectedUserContacts` | object/array | data | assign-menu selection | None | | | |
| `customList` / `taggedUserContacts` / `taggedGroups` | array | data | autocomplete / mentions | None | | | |
| `selectedFiles` / `invalidSelectedFiles` / `selectedAttachments` / `attachmentsToDelete` | array | data | composer files | None | | | |
| `localRecordedData` | array | data | staged recordings | None | | | |
| `sidebarMode` / `dialogMode` / `inboxMode` / `inlineCommentSectionMode` / `focusedThreadMode` / `pageModeComposer` | bool | ui | render-mode flags | `veltIf="!{sidebarMode}"` | 🔑 | | |
| `composerInOpenState` / `isInputFocused` | bool | ui | composer expanded / focused | `veltIf="{composerInOpenState}"` | 🔑 | | |
| `composerContent` / `composerContentHTML` (alias `newComment`/`newCommentHTML`) | string | ui | draft text / html | None | | | |
| `showReplies` / `collapsedComments` | bool | ui | replies shown / collapsed | None | 🔑 | | |
| `darkMode` / `readOnly` | bool | ui | theme / read-only | None | 🔑 | | |
| `selectedVisibility` / `selectedVisibilityUsers` | string/array | ui | visibility selection | None | | | |
| `isFocusedThreadEnabled` | bool | ui | focused-thread allowed | `veltIf="{isFocusedThreadEnabled}"` | 🔑 | | |
| `maxReplyAvatars` | number | ui | reply-avatar cap (default 5) | None | | | |
| `isTruncated` / `isExpanded` | bool | ui | message truncation / expanded | `veltIf="{isTruncated} && !{isExpanded}"` | 🔑 | | |
| `enableResolve` / `canResolveAnnotation` / `canUnresolveAnnotation` | bool | feature | resolve gates | `veltIf="{canResolveAnnotation}"` | 🔑 | | |
| `resolveStatusAccessAdminOnly` | bool | feature | resolve admin-only | \`veltIf="!{resolveStatusAccessAdminOnly} | | {isUserAdmin}"\` | 🔑 |
| `enableReactions` / `enableEdit` / `enableDelete` / `enableAttachment` / `enableAssignment` / `enableNotifications` / `enablePriority` / `enablePrivateMode` | bool | feature | per-feature gates | `veltIf="{enableReactions}"` | 🔑 | | |
| `replyAvatars` | bool | feature | show reply-avatar strip | `veltIf="{replyAvatars}"` | 🔑 | | |
| `userMentions` | bool | feature | @mentions on | `veltIf="{userMentions}"` | 🔑 | | |
| `visibilityOptions` / `seenByUsers` | bool | feature | visibility selector / seen-by | `veltIf="{seenByUsers}"` | 🔑 | | |
| `customStatusesShown` / `statusOptions` / `statusObj` | bool/array/object | feature/iter | status dropdown / options / per-item | `<velt-data field="statusObj.name">` | | | |
| `priorityOptions` / `priorityObj` | array/object | feature/iter | priority options / per-item | `<velt-data field="priorityObj.name">` | | | |
| `enableSignInButton` / `enableUpgradeButton` / `enableGhostCommentsMessage` | bool | feature | conditional buttons/banners | `veltIf="{enableSignInButton}"` | 🔑 | | |
| `suggestionMode` / `moderatorMode` / `enableAutoCategorize` / `isPlanExpired` | bool | feature | modes / plan | None | 🔑 | | |
| `showSuggestionModeActions` | bool | ui | show suggestion accept/reject actions | `veltIf="{showSuggestionModeActions}"` | 🔑 | | |
| `commentAcceptedStatus` / `commentRejectedStatus` | object | feature | suggestion accept/reject status objects (compare `.id`) | `veltClass="'accepted': {annotation.status.id} === {commentAcceptedStatus.id}"` | | | |
| `allowedFileTypes` / `allowedRecordings` / `screenSharingSupported` | array/bool | feature | attachment / recording limits | None | | | |
| `recordingSummaryEnabled` / `enterKeyToSubmit` / `deleteOnBackspace` / `deleteThreadWithFirstComment` | bool | feature | misc behavior | None | 🔑 | | |
| `bubbleOnPin` / `dialogOnHover` / `popoverMode` | bool | feature | render comment as bubble-on-pin / open dialog on hover / popover layout | `veltIf="{popoverMode}"` | 🔑 | | |
| `commentBubbleAvailable` | bool | ui | a comment bubble is available to show (gates bubble vs default view) | `veltIf="{commentBubbleAvailable}"` | 🔑 | | |
| `commentPlaceholder` / `replyPlaceholder` / `editCommentPlaceholder` / `editReplyPlaceholder` / `editPlaceholder` / `pageModePlaceholder` / `placeholder` | string | ui | composer/reply/edit placeholder strings (fallback `placeholder`) | `<velt-data field="commentPlaceholder"/>` | | | |
| `file` (`.uploading`) | object | iteration | per attachment (the invalid-attachments array is `invalidSelectedFiles`, above: there is **no** per-item `invalidFile` token) | `velt-class="'is-uploading': {file.uploading}"` | 🔑 | | |
| `view` / `userName` / `userEmail` / `viewedAt` | object/string | iteration | per seen-by viewer | `<velt-data field="view.user.name">` | | | |
| `option` / `item` | object | iteration | per visibility / custom-chip option | `<velt-data field="option.label"/>` | | | |
| `{i}` / `commentIndex` | number | iteration | loop index (0-based) | `veltIf="{i} === 0"` | 🔑 | | |

### Comment Bubble

*Access model: structured; some need full `globalConfigSignal.*` / `parentLocalUIState.*`.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `user` / `isUserAdmin` / `isKnownUser` | object/bool | app | user state | `veltIf="{isUserAdmin}"` | 🔑 |
| `annotation.status.id` / `.name` | string | data | status | `veltIf="{annotation.status.id} === 'OPEN'"` | 🔑 |
| `annotation.from.name` / `.priority.name` / `.assignedTo.name` | string | data | author / priority / assignee | `<VeltData field="annotation.from.name"/>` | |
| `annotation.comments.length` | number | data | reply count (→ CommentsCount slot) | `<VeltData field="annotation.comments.length"/>` | |
| `annotation.unreadCount` / `annotation.unread` | number/bool | data | unread (→ UnreadIcon) | `velt-class="'is-unread': {annotation.unread}"` | 🔑 |
| `annotation.iam.accessMode` | string | data | `'public'`/`'private'` | `veltIf="{annotation.iam.accessMode} === 'private'"` | |
| `annotation.ghostComment` | bool | data | lost target | `veltIf="{annotation.ghostComment}"` | 🔑 |
| `annotation.context.<key>` | object | data | context | `<VeltData field="annotation.context.label"/>` | |
| `annotations` / `unresolvedAnnotationsCount` / `unreadCount` | array/number | data | page totals | None | |
| `commentPinSelected` / `commentBubbleTargetPinHover` / `commentBubbleHover` / `openDialog` | bool | ui | selected / target-pin hover / bubble hover / open | `velt-class="'hover': {commentBubbleTargetPinHover}"` | 🔑 |
| `selectedAnnotationsMap` | object | ui | selection map | `velt-class="'selected': {selectedAnnotationsMap[annotation.annotationId]}"` | |
| `showAvatar` / `readOnly` / `darkMode` | bool | ui | avatar / read-only / theme | `veltIf="{showAvatar}"` | 🔑 |
| `commentCountType` / `variant` | string | ui | `'total'`/`'unread'` / variant | None | |
| `globalConfigSignal.featureState.customStatusesShown` / `.groupMatchedComments` / `.resolvedCommentsOnDom` / `.readOnly` | bool | feature | global feature flags | None | 🔑 |

### Comment Pin

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `user` / `isUserAdmin` | object/bool | app | user | `veltIf="{isUserAdmin}"` | 🔑 |
| `annotation.status.id` | string | data | status (→ marker color) | `veltIf="{annotation.status.id} === 'OPEN'"` | 🔑 |
| `annotation.priority.name` | string | data | priority label | `<VeltData field="annotation.priority.name"/>` | |
| `annotation.comments.length` | number | data | reply count (→ Number badge) | `<VeltData field="annotation.comments.length"/>` | |
| `annotation.unreadCount` | number | data | unread (→ UnreadCommentIndicator) | `veltIf="{annotation.unreadCount} > 0"` | |
| `annotation.visibility` | string | data | `'public'`/`'private'` (→ PrivateCommentIndicator) | `veltIf="{annotation.visibility} === 'private'"` | 🔑 |
| `annotation.context.<key>` | object | data | context | `<VeltData field="annotation.context.label"/>` | |

### Text Comment

*Access model: flat-config: `{componentConfig.<x>}`.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `user` / `user.name` / `isUserAdmin` / `isKnownUser` | object/bool | app | user | `<VeltData field="user.name"/>` | 🔑 |
| `annotation.status.id` / `.name` / `.from.name` / `.priority.name` | string | data | annotation fields | `veltIf="{annotation.status.id} === 'RESOLVED'"` | 🔑 |
| *(no `totalComments`)* | None | | Text Comment exposes **no** comment-count token; document-wide counts live on the sidebar (`commentAnnotationsCountByFilters` / `commentAnnotationsCountByStatus`) | None | |
| `position.top` / `position.left` | number | data | toolbar position | `<velt-data field="position.top">` | |
| `selectedWordsCount` / `selectedCharactersCount` | number | data | selection size | `velt-class="'has-words': {selectedWordsCount} > 0"` | |
| `showAdder` / `commentToolEnabled` / `isUserAllowed` / `enableTextComments` | bool | ui | adder / tool / permission / feature | `veltIf="{showAdder}"` | 🔑 |
| `rewriterEnabled` / `rewriterDefaultUIEnabled` | bool | ui | AI rewriter | `veltIf="{rewriterEnabled}"` | 🔑 |
| `uiState.disabled` / `uiState.isPlanExpired` | bool | ui | disabled / plan | `veltIf="{uiState.isPlanExpired}"` | 🔑 |
| `MIN_ALLOWED_WORDS_COUNT` / `MIN_`/`MAX_ALLOWED_CHARACTERS_COUNT` | number | ui | selection thresholds | None | |
| `darkMode` / `variant` / `parentLocalUIState.shadowDom` | bool/string | ui | theme / variant / shadow | None | 🔑 |

### Inline Comments Section

*Access model: structured.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `user` | object | app | current user | `<velt-data field="user.name">` | |
| `featureState.readOnly` / `.anonymousEmail` / `.messageTruncation` / `.messageTruncationLines` | bool/number | feature | feature gates | `veltIf="{featureState.anonymousEmail}"` | 🔑 |
| `annotations` / `allAnnotations` / `composerCommentAnnotation` / `statuses` | array/object | data | data | `veltIf="{composerCommentAnnotation}"` | 🔑 |
| `skeletonLoading` / `darkMode` | bool | ui | loading / theme | `veltIf="{skeletonLoading}"` | 🔑 |
| `filterState.filters` / `.filterDropdownOpen` | array/bool | ui | filter state | `velt-class="'open': {filterState.filterDropdownOpen}"` | 🔑 |
| `sortState.sortBy` / `.sortOrder` / `.sortingDropdownOpen` | string/bool | ui | sort state | `velt-class="'sort-{sortState.sortOrder}': true"` | 🔑 |
| `isResolvedCommentsOnDomFilterSelected` / `resolvedCommentsOnDom` | bool | ui | resolved filter | None | 🔑 |
| `multiThread` / `fullExpanded` / `readOnly` / `composerPosition` | bool/string | ui | layout | `velt-class="'multi-thread': {multiThread}"` | 🔑 |
| `*Placeholder` (comment/reply/composer/edit…) | string | ui | placeholder strings | `<velt-data field="commentPlaceholder">` | |
| `targetElementId` / `folderId` / `documentId` / `locationId` / `context` / `contextOptions` | string/object | ui | scope / context | `<velt-data field="context.something">` | |
| `filter` (`.id`/`.isSelected`/`.metadata`) | object | iteration | per filter item | `velt-class="'selected': {filter.isSelected}"` | 🔑 |
| `sortOption` / `sortOptionText` / `isActive` / `isAscending` | mixed | iteration | per sort option | `velt-class="'active': {isActive}"` | 🔑 |

### Multi-Thread Comment Dialog

*Access model: structured, per-instance.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `annotation` / `annotations` / `filteredAnnotations` | object/array | data | annotations | `<velt-data field="filteredAnnotations.length">` | |
| `multiThreadAnnotationId` / `multiThreadCommentAnnotation` / `nonDraftCommentsCount` | string/object/number | data | thread data | None | |
| `data.user` / `context` / `data.contextId` / `containerComponentId` | object/string | data | user / context | `<velt-data field="context.foo">` | |
| `commentPinSelected` / `commentPinType` | bool/string | ui | pin selected / type | `velt-class="'pin-selected': {commentPinSelected}"` | 🔑 |
| `inboxMode` / `readOnly` / `hideMultiThreadAnnotationComposer` | bool | ui | modes | `veltIf="!{hideMultiThreadAnnotationComposer}"` | 🔑 |
| `minimalFilter` (`all`/`read`/`unread`/`resolved`) | string | ui | minimal filter | `velt-class="'filter-{minimalFilter}': true"` | |
| `minimalFilterDropdownOpen` / `minimalActionsDropdownOpen` | bool | ui | dropdowns open | `velt-class="'open': {minimalFilterDropdownOpen}"` | 🔑 |
| `noCommentsFound` / `noCommentsFoundForAppliedFilters` | bool | ui | empty states | `veltIf="{noCommentsFound}"` | 🔑 |
| `darkMode` / `dialogVariant` / `variant` / `uiState.shadowDom` | bool/string | ui | theme / variants / shadow | None | 🔑 |
| `isSelected` | bool | iteration | minimal filter/sort item selected | `velt-class="'is-selected': {isSelected}"` | 🔑 |

### Autocomplete (@mentions)

*Access model: flat-config.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `componentConfig.flattenedItems` | array | data | visible options (empty-state: `length === 0`) | `<velt-data field="componentConfig.flattenedItems.length">` | |
| `componentConfig.contactsWithoutGroup` / `.groups` | array | data | ungrouped contacts / groups | None | |
| `componentConfig.newUserContact` / `.newUserContactError` | object/string | data | new contact / error | `veltIf="{componentConfig.newUserContactError}"` | 🔑 |
| `componentConfig.customAutocompleteSearch` / `.expandMentionGroups` / `.showMentionGroupsFirst` / `.showMentionGroupsOnly` / `.customGroupsEnabled` | bool | ui | search / group modes | None | 🔑 |
| `option` (`.user`/`.group`/`.name`/`.email`/`.description`) | object | iteration | one option | `<velt-data field="option.name">` | |
| `chip` (`.label`) | object | iteration | inline mention chip | `<velt-data field="chip.label">` | |

### Comments Sidebar

*Access model: flat-config: `{componentConfig.<x>}`.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `componentConfig.sidebarVisible` / `.darkMode` / `.fullScreen` / `.fullExpanded` | bool | ui | visibility / theme / size | `velt-if="{componentConfig.sidebarVisible}"` | 🔑 |
| `componentConfig.embedMode` / `.floatingMode` / `.pageMode` / `.readOnly` / `.sidebarReadMode` | string/bool | ui | layout/mode | `velt-class="'page-mode': {componentConfig.pageMode}"` | 🔑 |
| `componentConfig.skeletonLoading` / `.noCommentsFound` / `.noCommentsFoundForAppliedFilters` | bool | ui | loading / empty | `velt-if="{componentConfig.skeletonLoading}"` | 🔑 |
| `componentConfig.moreFiltersVisible` | bool | ui | filter panel open | None | 🔑 |
| `componentConfig.filterPanelLayout` | string | ui | filter-panel layout class (controls panel arrangement) | `velt-class="'{componentConfig.filterPanelLayout}': true"` | |
| `componentConfig.groupBy` / `.groupByOptions` | string/array | ui | current group-by key / available group-by options | `velt-if="{componentConfig.groupBy} === 'status'"` | |
| `componentConfig.documentFilterDropdownOpen` / `.minimalFilterDropdownOpen` / `.locationFilterDropdownOpen` / `.minimalActionsDropdownOpen` | bool | ui | per-dropdown open flags | `velt-class="'open': {componentConfig.minimalFilterDropdownOpen}"` | 🔑 |
| `componentConfig.searchPlaceholder` / `.commentPlaceholder` / `.replyPlaceholder` / `.editPlaceholder` / `.editCommentPlaceholder` / `.editReplyPlaceholder` / `.pageModePlaceholder` | string | ui | placeholder strings | `<velt-data field="componentConfig.searchPlaceholder"/>` | |
| `componentConfig.filterConfig` / `.filters` / `.systemFiltersOperator` | object/string | ui/data | filter config / values / AND-OR | `<velt-data field="componentConfig.filters.statuses.length">` | |
| `componentConfig.virtualScrollData` / `.commentAnnotationsCountByFilters` / `.searchQuery` / `.taggedFilters` | array/object/string | data | data (people/tag filters are `taggedFilters`: there is **no** `selectedFilterTags`) | None | |
| `focusedAnnotation` | object | data | focused thread | `<velt-data field="focusedAnnotation.from.name">` | |
| `appliedFiltersCount` / `filteredCommentAnnotationsCount` / `unreadCommentAnnotationCount` | number | ui/data | counts/badges | `<velt-data field="appliedFiltersCount">` | |
| `annotation` / `group` (`.expanded`/`.name`/`.count`) / `filter` / `item` / `tag` | object | iteration | loop-scoped | `velt-class="'expanded': {group.expanded}"` | 🔑 |

### Notifications Panel & Tool

*Access model: structured; short names.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `notification` (`.type`/`.from.name`/`.read`/`.createdAt`/`.documentName`/`.count`) | object | data | per notification | `veltIf="{notification.type} === 'comment'"` | 🔑(read) |
| `notifications` / `notificationsForYouInSession` / `notificationsInSession` | array | data | feeds | `<velt-data field="notifications.length">` | |
| `notificationsByUserMap` / `notificationsByDocumentId` / `notificationsByDate` | object/array | data | grouped feeds | None | |
| `unreadNotificationsForYou` / `currentDocumentName` | number/string | data | unread badge / doc name | None | |
| `settingsConfig` / `settingsSelectedOption` | array/object | data | settings tree / selection | None | |
| `selectedTab` (`forYou`/`all`/`documents`/`people`) / `TABS` / `tabConfig` / `tabPage` / `tabCount` | string/object | ui | tab state | `veltIf="{tabConfig.forYou}"` | |
| `panelOpenMode` / `settingsLayout` / `pageSize` | string/number | ui | layout | None | |
| `settingsOpen` / `settingsMutedAll` / `notificationsPanelVisible` | bool | ui | settings / mute / open | `velt-class="'settings-open': {settingsOpen}"` | 🔑 |
| `settingsAccordionExpanded` / `usersExpanded` / `documentExpanded` | object | ui | per-key expanded maps | `velt-class="'expanded': {usersExpanded[notification.from.email]}"` | |
| `settingsEnabled` | bool | feature | settings available | `veltIf="{settingsEnabled}"` | 🔑 |
| `isLoadMoreVisible` / `isAllRead` | bool | ui | load-more / all read | `veltIf="{isLoadMoreVisible}"` | 🔑 |
| *(Tool)* `considerAllNotifications` / `panelShadowDom` | bool | feature/ui | count all / panel shadow | None | 🔑 |

### Reactions

*Access model: flat-config.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `componentConfig.annotation` (`.emoji`/`.reactions`/`.users`) / `.annotations` | object/array | data | reaction data | `<velt-data field="componentConfig.annotation.emoji">` | |
| `componentConfig.isReactionSelectedByCurrentUser` | bool | app | local user reacted | `velt-class="'is-mine': {componentConfig.isReactionSelectedByCurrentUser}"` | 🔑 |
| `componentConfig.type` | string | ui | pin type (`comment`/`inline`/`timeline`/`standalone`) | `velt-class="'pin-{componentConfig.type}': true"` | |
| `componentConfig.disableTooltip` / `.tooltipVisible` | bool | ui | tooltip suppress / open | `velt-if="!{componentConfig.disableTooltip}"` | 🔑 |
| `componentConfig.skeletonLoading` / `.darkMode` / `.shadowDom` / `.variant` / `.excludeReactionIds` | bool/string/array | ui | loading/theme/shadow/exclusions | None | 🔑 |
| `emoji.key` / `.value` / `.name` | string | iteration | picker emoji | `<velt-data field="emoji.value">` | |
| `isSelected` | bool | iteration | emoji selected | `velt-class="'is-selected': {isSelected}"` | 🔑 |

### Presence

*Access model: flat-config.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `componentConfig.filteredPresenceUsers` | array | data | active users (gate: `length > 0`) | `<velt-data field="componentConfig.filteredPresenceUsers.length">` | |
| `componentConfig.user` | object | data | local user (hover user in tooltip) | None | |
| `componentConfig.maxUsers` | number | ui | avatar cap (default 5) | None | |
| `componentConfig.isActive` *(tooltip)* | bool | app | active state (no `lastActiveAt` token: away state comes from `presenceUser.onlineStatus`) | None | 🔑 |
| `componentConfig.shadowDom` / `.variant` | bool/string | ui | shadow / variant | None | 🔑 |
| `presenceUser` (`.name`/`.email`/`.onlineStatus`/`.color`) / `index` | object/number | iteration | per avatar | `velt-class="'away': {presenceUser.onlineStatus} === 'away'"` | 🔑 |

### Cursor

*Access model: flat-config.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `componentConfig.user` / `.cursorUsers` / `.currentCursorUser` / `.cursorUser` | object/array | data | local / remote pointers / per-pointer | `<velt-data field="componentConfig.cursorUser.name">` | |
| `componentConfig.selfCursorPointer` | bool | app | pointer is local user | `velt-class="'is-self': {componentConfig.selfCursorPointer}"` | 🔑 |
| `componentConfig.showDefault` / `.showAvatar` / `.showAudio` / `.showVideo` | bool | ui | render-mode toggles | `veltIf="{componentConfig.showAvatar}"` | 🔑 |
| `componentConfig.huddleJoined` / `.huddleOnCursorMode` / `.isFirstComponent` | bool | app | huddle / first instance | `veltIf="{componentConfig.huddleJoined}"` | 🔑 |
| `componentConfig.gainVolume` / `.lightenedColor` / `.variant` / `.stream` | number/string/Stream | ui/feature | ring level / color / variant / media | `veltIf="{componentConfig.stream}"` | |

### Huddle

*Access model: flat-config.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `componentConfig.meetingJoined` | bool | app | local user in huddle | `velt-class="'in-huddle': {componentConfig.meetingJoined}"` | 🔑 |
| `componentConfig.localStreamState.audioState` / `.videoState` / `.screenSharingState` | bool | app | mic / cam / screen | `velt-class="'audio-on': {componentConfig.localStreamState.audioState}"` | 🔑 |
| `componentConfig.huddleAttendees` | array | data | attendees | `<velt-data field="componentConfig.huddleAttendees.length">` | |
| `componentConfig.attendee` / `.color` / `.gainVolume` | object/string/number | data/ui | per tile (no `attendee.isLocal`; local-vs-remote is `!componentConfig.isRemoteStream`) | None | |
| `componentConfig.type` | string | ui | tool type (audio/video/presentation/all) | `velt-class="'tool-{componentConfig.type}': true"` | |
| `componentConfig.screenSharingSupported` / `.disabled` / `.isDragging` / `.bannerRemoved` | bool | ui/app | support / state | `velt-class="'dragging': {componentConfig.isDragging}"` | 🔑 |
| `componentConfig.isFirstComponent` | bool | app | first instance | `veltIf="{componentConfig.isFirstComponent}"` | 🔑 |

### Recorder

*Access model: flat-config: use full `componentConfigSignal.` for collisions.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `recordingInProgress` / `isRecording` / `isPlaying` | bool | state | recording / running / playback | `velt-class="'recording': {componentConfigSignal.recordingInProgress}"` | 🔑 |
| `recordingType` / `types` / `recorderModes` | string/array/object | data | active type / permitted / id map | None | |
| `screenSharingSupported` / `recordingCountdown` / `recordingTranscriptionEnabled` | bool | feature | support / countdown / transcript | `velt-if="{componentConfigSignal.screenSharingSupported}"` | 🔑 |
| `recorderPinAnnotation` / `recorderPinSelected` / `multipleRecorderPinsSelected` / `dragging` | object/bool | data/state | pin + selection | `velt-class="'selected': {componentConfigSignal.recorderPinSelected}"` | 🔑 |
| `attachment` / `annotation` / `user` / `recorderInitData` | object | data | media / annotation / author | `<velt-data field="componentConfigSignal.attachment.url">` | |
| `totalTimeValue` / `currentTimeValue` / `recordedTime` | number | data/state | durations (the elapsed value is `recordedTime`: there is **no** `elapsedTime` token) | None | |
| `mode` / `sourceFeature` / `videoContainerHovered` | string/bool | ui/state | floating-vs-thread / origin / hover | `velt-class="'mode-{componentConfigSignal.mode}': true"` | 🔑(hover) |
| `buttonLabel` / `darkMode` / `disabled` / `variant` / `shadowDom` | string/bool | ui | label / theme / state | None | 🔑(bools) |

### Transcription

*Access model: flat-config.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `mode` | string | ui | floating / sidebar / summaryMode | `velt-if="{componentConfig.mode} === 'floating'"` | |
| `transcription` / `vttFileTextArray` | object/array | data | transcript / segments | `<velt-data field="componentConfig.transcription">` | |
| `transcriptionVisible` / `sidebarVisible` / `subtitlesVisible` / `dialogVisible` | bool | state | visibility flags | `velt-class="'visible': {componentConfig.transcriptionVisible}"` | 🔑 |
| `highlightedTextIndex` | number | state | active segment | None | |
| `showMoreSummary` / `darkMode` / `showDefaultBtn` | bool | state/ui/feature | summary expand / theme / default btn | `veltIf="{componentConfig.showDefaultBtn}"` | 🔑 |

### Activity Log

*Access model: structured.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `user` / `darkMode` / `isEnabled` | object/bool | app/feature | user / theme / enabled | `velt-if="{isEnabled}"` | 🔑 |
| `allActivities` / `filteredActivities` / `groupedActivities` / `virtualScrollItems` | array | data | activity records | `velt-if="{allActivities.length} > 0"` | |
| `activeFilter` / `availableFilters` | string/array | state/data | active filter / options | `velt-class="'filter-active': {activeFilter} !== 'all'"` | |
| `isOpen` / `filterDropdownOpen` / `expandedGroups` | bool/Set | state | panel / dropdown / expanded | `velt-class="'is-open': {isOpen}"` | 🔑 |
| `defaultVisibleCount` / `variant` | number/string | ui | per-group count (5) / variant | None | |
| `dateGroup` (`.displayLabel`/`.totalCount`) / `activity` (`.user`/`.action`/`.target`/`.detail`) / `filter` | object | iteration | per row | `<velt-data field="activity.user.name">` | |
| `isActive` / `isExpanded` / `remainingCount` | bool/number | iteration | per-item state | `velt-class="'expanded': {isExpanded}"` | 🔑 |

### View Analytics

*Access model: flat-config.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `componentConfig.todayViewsCount` / `.totalUniqueViewsCount` | number | data | counts | `<velt-data field="componentConfig.todayViewsCount">` | |
| `componentConfig.views` / `.usersMap` / `.userViews` | object/array | data | views / viewers | `<velt-data field="componentConfig.userViews.length">` | |
| `componentConfig.treadsVisible` | bool | state | dialog open *(SDK spelling: "treads")* | `velt-class="'dialog-open': {componentConfig.treadsVisible}"` | 🔑 |
| `componentConfig.bottomSheetMode` / `.customButtonAdded` / `.isPhone` | bool | state/feature | bottom-sheet / custom btn / mobile | `velt-if="!{componentConfig.customButtonAdded}"` | 🔑 |

### Comments Tool

*Access model: structured; `componentConfig.data.*` / `.uiState.*`.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `commentToolEnabled` / `addCommentMode` / `popoverMode` / `groupMatchedComments` | bool | feature/state | enabled / add-mode / popover / grouping | `velt-class="'add-mode': {addCommentMode}"` | 🔑 |
| `componentConfig.data.commentAnnotationAvailable` | bool | feature | comments placeable here | `velt-if="{componentConfig.data.commentAnnotationAvailable}"` | 🔑 |
| `componentConfig.data.context` / `.targetElementId` / `.documentId` / `.locationId` / `.disabled` | object/string/bool | data | context / scope / disabled | `<velt-data field="componentConfig.data.context.foo">` | 🔑(disabled) |
| `componentConfig.uiState.showDefaultBtn` / `.shadowDom` / `.darkMode` / `.contextInPageModeComposer` | bool | ui | default btn / shadow / theme / page-mode context | `velt-if="{componentConfig.uiState.showDefaultBtn}"` | 🔑 |

### Sidebar Button

*Access model: structured.*

| name | type | bucket | meaning | example | 🔑 |
| - | - | - | - | - | - |
| `globalConfig.featureState.sidebarVisible` | bool | feature | sidebar open | `velt-class="'sidebar-open': {globalConfig.featureState.sidebarVisible}"` | 🔑 |
| `componentConfig.data.annotations` / `.unreadCount` | array/number | data | annotations / unread | `<velt-data field="componentConfig.data.unreadCount">` | |
| `componentConfig.uiState.showDefaultBtn` / `.floatingMode` / `.floatingModeSidebarVisible` / `.darkMode` / `.commentCountType` / `.variant` | bool/string | ui | button / floating / theme / count type | `velt-if="{componentConfig.uiState.showDefaultBtn}"` | 🔑(bools) |

### Area · Arrow · Selection · Rewriter

*Access model: flat-config.*

| feature | key variables |
| - | - |
| **Area** | `componentConfig.areaPinAnnotation`, `.commentPinAnnotation`, `.selected` 🔑, `.hideAreaAnnotation` 🔑, `.isResizing` 🔑, `.areaAnnotationColor` (default `#625DF5`), `.areaProperties` |
| **Arrow** *(no wireframe slots yet: CSS/`[template]` only)* | `componentConfig.arrowPinAnnotation`, `.annotationDragging` 🔑, `.selectedAnnotationsMap` |
| **Selection** | `componentConfig.position`, `.userIndicatorPosition` (`start`/`end`), `.userIndicatorType` (`Avatar`/`Name`), `.selections` |
| **Rewriter** | `componentConfig.options`, `.first` 🔑 / `.last` 🔑, `.loading` 🔑, `.bottomSheetMode` 🔑, `.isPhone` 🔑, `.selectedOptionIndex` |

### Tags

**No wireframe variables / slots.** Customize via the `[template]` input on `velt-tag-pin` / `velt-tag-dialog`, CSS, or the headless `useTagAnnotations` / `useTagUtils` hooks. See [`Annotations, tags, arrows, and areas`](https://velt.dev/docs/ui-customization/features/annotations-tags-arrows-areas).

***


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