> ## Documentation Index
> Fetch the complete documentation index at: https://velt-codex-ui-customization-guide-refresh.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Wireframe tokens & variables

> Use wireframe directives, conditions, classes, and data tokens in custom Velt templates.

<Note>
  **Source of truth: exhaustive for what it covers.** Generated from Velt directive metadata.

  * **If a name isn't on this page, it doesn't exist**: don't use it (a missing identifier resolves to `undefined` / renders nothing).
  * Never invent or guess a name; use only identifiers that appear verbatim here or that you verified against ground truth and added here.
  * *Scope: this page is exhaustive for the directive **syntax**: the `velt-if` / `velt-class` / `velt-class-<name>` / `velt-data` directives and the `{…}` token grammar (operators, nested access, the three usage forms). The **slot catalog** (which `*-wireframe` slots each component exposes) is delegated to [`Wireframe components`](/ui-customization/reference/wireframe-components); the **variable catalog** (every `{name}` per component) is delegated to [`Wireframe variables`](/ui-customization/template-variables).*
</Note>

How to read live state inside a wireframe. Used by [`Wireframes`](/ui-customization/layout).

This page is the **syntax** (operators, nested access, the three usage forms). For the **complete variable catalog** (every `{name}`, grouped by feature, with the 🔑 state flags) see [`Wireframe variables`](/ui-customization/template-variables).

<Warning>
  A token not in [`Wireframe variables`](/ui-customization/template-variables) resolves to `undefined`: only use names listed there ([source-of-truth invariant](/ui-customization/reference/source-of-truth-invariant)).
</Warning>

***

## Token syntax

A token is `{…}`. The resolver matches `/\{(.*?)\}/g` and supports nested paths:

```text theme={null}
{user.name}                               property access
{annotation.comments.length}              array length
{annotation.comments.0.text}              array index (dot)
{annotation.comments[0].from.userId}      array index (bracket)
{unreadCommentsMap[annotation.annotationId]}   dynamic key (inner resolved first)
{annotation.context.foo}                  annotation.context shorthand
```

## The three usage forms

| You want to…           | React / Next.js                                                                                                                           | Other Frameworks                                                |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| Print a value as text  | `<VeltData field="user.name" />`                                                                                                          | `<velt-data field="user.name"></velt-data>`                     |
| Show/hide on a boolean | `<VeltIf condition="{enableResolve}">…</VeltIf>` (group) or the `veltIf` prop on a wireframe component (single slot)                      | `<velt-if condition="…">…</velt-if>` or the `velt-if` attribute |
| Toggle CSS classes     | `veltClass` prop on a wireframe component; on your own markup inside a wireframe, the literal `velt-class="…"` attribute works in JSX too | `velt-class="'cls': {…}, …"` or `velt-class-<name>="{…}"`       |

> Booleans are most useful in `velt-if`/`velt-class`; strings/numbers/dates in `velt-data`; compound objects via deep paths (e.g. `field="annotation.from.name"`).

### Show or hide a group with `VeltIf`

Wrap wireframe components and custom markup in `VeltIf` when the same condition should apply to a group of elements.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    <VeltIf condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 3">
      <p>This annotation is open and has three comments.</p>
    </VeltIf>
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <velt-if condition="{annotation.status.id} === 'OPEN' && {annotation.comments.length} === 3">
      <p>This annotation is open and has three comments.</p>
    </velt-if>
    ```
  </Tab>
</Tabs>

### Show or hide one wireframe slot

Use the `velt-if` attribute when the condition applies to a single wireframe component.

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    <VeltCommentDialogWireframe.Header veltIf="{user.isAdmin} === true" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <velt-comment-dialog-header-wireframe velt-if="{user.isAdmin} === true">
    </velt-comment-dialog-header-wireframe>
    ```
  </Tab>
</Tabs>

### Print a value with `VeltData`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // Display the user name
    <VeltData field="user.name" />

    // Nested properties work
    <VeltData field="annotation.from.name" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <velt-data field="user.name"></velt-data>

    <velt-data field="annotation.from.name"></velt-data>
    ```
  </Tab>
</Tabs>

<Warning>
  `field="context.someProperty"` resolves from the component's **local UI state** context (e.g. the Inline Comments Section's own `context`), **not** from the annotation. To read context stored on the annotation, use `field="annotation.context.someProperty"`.
</Warning>

### Toggle CSS classes with `velt-class`

<Tabs>
  <Tab title="React / Next.js">
    ```jsx theme={null}
    // On a wireframe component: the veltClass prop
    <VeltCommentDialogWireframe.Header veltClass="'is-dark': {darkMode}" />

    // On your own markup inside a wireframe: the literal attribute passes through JSX
    <div velt-class="'is-dark': {darkMode}, 'is-resolved': {resolved}" />
    <div velt-class-active="{showReplies}" />
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```html theme={null}
    <div velt-class="'is-dark': {darkMode}, 'is-resolved': {resolved}"></div>
    <div velt-class-active="{showReplies}"></div>
    ```
  </Tab>
</Tabs>

## Operators allowed in `velt-if`

| Category   | Supported                                                    |
| ---------- | ------------------------------------------------------------ |
| Logical    | `&&`, `\|\|`, `!`                                            |
| Equality   | `==`, `!=`, `===`, `!==`                                     |
| Comparison | `<`, `>`, `<=`, `>=`                                         |
| Grouping   | `(`, `)`                                                     |
| Literals   | strings `'…'`, numbers, `true`, `false`, `null`, `undefined` |

Examples: `condition="{enableResolve} && {canResolveAnnotation}"`, `condition="{commentIndex} === 0"`, `condition="!{noCommentsFound}"`. Anything outside this whitelist is stripped before evaluation (safe by design).

## Strict CSP policy

Some environments enforce a strict Content Security Policy that disallows `unsafe-eval`. If your CSP blocks condition evaluation, enable Velt's safe evaluator before rendering your wireframes.

<Tabs>
  <Tab title="React / Next.js">
    ```tsx theme={null}
    const { client } = useVeltClient();

    client.enableSafeEval();
    // client.disableSafeEval();
    ```
  </Tab>

  <Tab title="Other Frameworks">
    ```js theme={null}
    Velt.enableSafeEval();
    // Velt.disableSafeEval();
    ```
  </Tab>
</Tabs>

***

## Mapped vs. flat-config features (which name form to use)

Two access conventions exist, as a rule of thumb:

* **Mapped: use 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.
* **Flat-config: use the explicit** `{componentConfig.<name>}` form: 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` in a flat-config feature, fall back to `{componentConfig.<name>}`. Mapped features accept the explicit form too; it's just not required.

## Variables that support nested access

Only these root names allow `{root.nested.field}`; any other variable resolves to its root only. (Per-component variable lists with examples: [`Wireframe variables`](/ui-customization/template-variables).)

```
user, annotation, annotations, allAnnotations, userContact, comment, commentAnnotation,
commentAnnotations, recorderInitConfig, ghostComment, editComment, assignTo, customChipData,
currentDialogView, context, focusedAnnotation, notification, selectedMinimalFilterDropdownOption,
unreadNotificationsForYou, notificationsForYouInSession, notificationsInSession,
notificationsByUserMap, notificationsByDocumentId, notificationsByDate, settingsConfig,
settingsSelectedOption, settingsAccordionExpanded, tabConfig, tabPage, TABS, allActivities,
filteredActivities, groupedActivities, virtualScrollItems, availableFilters, expandedGroups,
activity, activityRecord, dateGroup, filter, filterOption, position, allowedElementIds,
filteredAnnotations, multiThreadCommentAnnotation, composerCommentAnnotation, statuses,
filterState, sortState, selectedAnnotationsMap, selectedAnnotationsLocationMap, contextOptions
```

If a deep path returns `undefined`, first check the root is on this list.

***

## Frequently used variables (Comment Dialog / Sidebar)

A small starter set: see the per-feature page for the full list and types:

| Variable                                    | Meaning                                              | Typical use                               |
| ------------------------------------------- | ---------------------------------------------------- | ----------------------------------------- |
| `{user}` / `{user.name}`                    | Current user                                         | `velt-data`                               |
| `{annotation}`                              | The thread's annotation (deep paths OK)              | `velt-data` (e.g. `annotation.from.name`) |
| `{comment}` / `{commentIndex}`              | Current comment in a thread card / its 0-based index | `velt-if="{commentIndex} === 0"`          |
| `{darkMode}`                                | Dark mode active                                     | `velt-class`                              |
| `{noCommentsFound}`                         | Sidebar empty state                                  | `velt-if`                                 |
| `{enableResolve}`, `{canResolveAnnotation}` | Resolve availability                                 | `velt-if`                                 |
| `{resolved}` / `{status}`                   | Thread resolved / status                             | `velt-if` / `velt-class`                  |
| `{composerInOpenState}`                     | Composer expanded                                    | `velt-class`                              |
| `{focusedAnnotation}`                       | Sidebar's focused thread                             | `velt-data`                               |
| `{notification}`                            | Current notification (notifications panel)           | `velt-data`                               |

***

## Debugging a token that shows nothing

If a token renders `undefined`/blank, check, in order:

1. **Spelling**: exact name from [`Wireframe variables`](/ui-customization/template-variables) (case-sensitive).
2. **Nested access**: is the root in the nested-access list above? If not, you can only read its root.
3. **Context**: are you inside a slot that actually receives that variable? (e.g. `{comment}`/`{commentIndex}` exist only inside thread-card descendants; `{notification}` only in the notifications panel.)
4. **Mapped vs flat**: for flat-config features use `{componentConfig.<name>}`.

> The full variable list (and which roots allow nested access) is in [`Wireframe variables`](/ui-customization/template-variables).
