Skip to main content
Velt gives you the data and the actions; you build 100% of the UI with your own components. Velt renders nothing. Use it when the design needs your own interactive components inside the collaboration UI, a layout wireframe slots can’t express, or you’re rendering comments onto a surface Velt can’t draw into (a PDF, canvas, or video timeline). Don’t when a wireframe could express the layout: headless is the most expensive layer, and you own everything it gives up.
Hooks are React-only. In other frameworks the same data and actions live on the Velt client’s elements (Velt.getCommentElement()), shown in the Other Frameworks tabs below. Full mapping: API methods.

The model

Three kinds of hooks (full list in Hooks; each maps to a client API method for other frameworks, e.g. useAddCommentcommentElement.addComment()):
  • Read: useCommentAnnotations, useCommentAnnotationById, useUnreadCommentCountOnCurrentDocument, useCommentModeState, … → reactive data you render.
  • Mutate: useAddCommentAnnotation, useAddComment, useUpdateComment, useDeleteComment, useResolveCommentAnnotation, useUpdateStatus, useToggleReaction, … → call these from your own buttons.
  • Control: useVeltClient, useSetDocuments, useIdentify, useVeltInitState, … → init, scope, imperative control.
You render the read hooks’ data and wire your UI’s events to the mutate hooks. Velt still handles storage, sync, mentions, and permissions: you’re only replacing the view.
Middle ground: keep Velt’s components but strip their visual styling with setUnstyledMode() (v6.0.0-beta.10+) and bring your own CSS. Far less work than headless. See unstyled mode.

Steps

1

Render data from a read source

The read source is reactive: it updates whenever comments change, including other users in real time. You never poll.
2

Wire your buttons to actions

Your components are fully interactive, unlike wireframes. Call the actions from your own handlers:
3

Build objects to the SDK data model

Mutations expect objects shaped like Velt’s types (from @veltdev/types), and you construct them yourself:
For addComment and updateComment, the Comment needs: commentId (auto if omitted), type ('text' | 'voice', default 'text'), from (a full User), commentText, commentHtml, status ('added' | 'updated'), and any array fields you touch. from is the field most often missed, and missing fields are the most common headless bug.

Request objects

Actions take a single request object, not loose arguments. The same methods exist on Velt.getCommentElement() with identical names and shapes. Required fields only; all also accept options?: The current shapes are the *Request interfaces in @veltdev/types (AddCommentRequest, UpdateStatusRequest, …). Read the type if a call errors.

What it can and can’t do

If a wireframe can express the layout, prefer it: you keep Velt’s behavior for free and only restyle. Not sure? Point the UI Customization Plugin at your design and it will tell you whether a cheaper layer covers it.

Troubleshooting

Common headless symptoms, in Debugging:

Checklist

  • Using real hook names from Hooks.
  • Objects passed to mutations match @veltdev/types, with every required field.
  • Reactive data comes from read hooks; no manual polling.
  • You’ve confirmed a wireframe genuinely can’t do it.