Skip to main content
A fast, ordered playbook for the things that actually go wrong. Find your symptom, apply the fix. (Many of these are also in Edge cases and limitations; this page is the action-first version.)

First, always

  1. Turn on debug logs. Set forceDebugMode in sessionStorage (sessionStorage.setItem('forceDebugMode','true')) and reload: Velt logs verbosely.
  2. Confirm Velt is initialized. Gate on useVeltInitState(). If it’s never true, fix setup (API key, identify, setDocuments) before debugging UI: you can’t style what isn’t rendering.
  3. Compare against default. Temporarily remove your customization. If the default works and yours doesn’t, it’s your customization; if the default is also broken, it’s setup/data.
  4. Inspect the element. With shadowDom={false}, open DevTools on the element: read its real velt-* classes/attributes and where it sits in the DOM.

Symptom → cause → fix

”My CSS does nothing”

  • Shadow DOM is on. Variables cross it, but class/selector CSS doesn’t → either set shadowDom={false}, or keep it on and push your CSS into the shadow root with client.injectCustomCss({ type:'styles', value:'…' }).
  • Specificity. Velt injects high-specificity styles → add !important. Inspect → target the velt-* class → !important.
  • Wrong class. You guessed a class name → inspect and use the actual velt-* class (CSS classes).

”My wireframe renders nothing”

  • Feature component not mounted. A Velt…Wireframe only registers a template: you must also mount the live feature (VeltComments / VeltCommentsSidebar / VeltCommentDialog).
  • Two <VeltWireframe> roots. Merge is first-with-content-wins → your template may be ignored. Use one.
  • Wrong slot name. Verify against Wireframe components.
  • List/repeater slot. Custom layout around a list slot is ignored: customize the item wireframe instead (Wireframes).

”My wireframe markup shows up inline on the page (not inside the Velt component), and the component still uses defaults”

  • No <VeltWireframe> registry root wrapping your slot templates. A slot element placed directly in the page (without the <VeltWireframe> root) renders its children inline where it sits and the live component falls back to its default UI because the template was never registered. Wrap all slot templates in exactly one <VeltWireframe> root (in plain HTML: one <velt-wireframe>).

”My wireframe’s empty state (or one piece) works, but the header/search/list vanished”

  • You declared a container/root slot and omitted its structural children. For example, declaring velt-comments-sidebar-v2-wireframe with only a custom empty-placeholder renders the empty state but drops the search/filter/list. Container slots replace their layout: re-declare every structural child you want (panel → header(search,filter) → list → empty-placeholder). Leaf slots fall back to default; containers do not (Wireframes).

”My wireframe applies in the wrong places (or not where I want)”

  • Scoping. Nested child wireframe = scoped to that parent’s render; root-level child = global. Move it accordingly (Wireframes).
  • First-with-content-wins. If the same component is registered both nested and at root, the first one with content wins: don’t register it both ways.

”A button/onClick/hook inside my wireframe does nothing”

  • Expected: wireframe markup is cloned; React interactivity is stripped (the interactivity rule). Use the Velt slot for built-in actions, or VeltButtonWireframe + useVeltEventCallback('veltButtonClick') for custom actions (Patterns and tips). For real interactive components, use primitives.

velt-data shows blank / velt-if never matches”

  • Wrong/undefined variable. Names are case-sensitive and finite: check Template Variables. A wrong name → undefined.
  • Wrong context. Some variables exist only in certain slots ({comment}/{commentIndex} only inside a thread card; {notification} only in the notifications panel; {focusedAnnotation} only in the sidebar).
  • Nested access not supported. Only the roots in the nested-access list allow {root.nested}; others resolve to root only.
  • Flat-config feature. Try the explicit {componentConfig.<name>} form (cursor/presence/huddle/recording/reactions/area/arrow/tag/autocomplete).

”My sidebar/list won’t scroll, or overflows / won’t take the available height”

  • Broken flex/height chain: including Velt’s internal elements. Every element from your wrapper down to the scroll container needs min-height:0 (plus flex:1 / height:100%): including Velt’s own internal containers (e.g. app-comment-sidebar-panel) that sit between your layout and the list. Inspect to find the hidden link and force it (often with !important). One missing link kills the scroll. (Full recipe in Patterns and tips.) Re-test that scrolling actually works: it’s easy to get 90% right and still have a dead scroll.

”Default styling is still there even though I wireframed it”

  • Expected: a wireframe replaces a slot’s content, not all the surrounding default styling (borders, padding, backgrounds, fixed widths, popover chrome). Inspect → find the velt-* class → override with !important. Treat this as part of every wireframe pass.

”My dialog/pin/primitive renders in the wrong place (top-left, escaping its box)”

  • Absolute positioning needs a positioned ancestor. Some Velt pieces use position: absolute. Give the parent you mount them in position: relative so they anchor correctly. (Recipe in Patterns and tips.)

”Dark mode colors are wrong”

  • Hard-coded colors. Move dark values under :root[data-velt-theme="dark"] using --velt-dark-mode-*.

”A primitive layout won’t compose / a child won’t restructure”

  • Leaf component. Leaf primitives have no sub-components → restructure via that leaf’s wireframe instead (Primitives).
  • You forgot the composition. Primitives don’t auto-loop: fetch the data, .map(), pass annotationId/comment yourself.

”Headless mutation does nothing / errors”

  • Object shape. Hand-built Comment/CommentAnnotation is missing required fields → fill every field the action needs; read the type in @veltdev/types.
  • Wrong hook usage. Most hooks return an object: const { addComment } = useAddComment(). Read-hook returns are often wrappers (e.g. …Count{ count }): read the field (Hooks).

”SSR / hydration error (Next.js)”

  • Mark customization + hook components 'use client'; gate on useVeltInitState(); don’t expect Velt UI during SSR.

When you’re still stuck

  • Re-check the reference pages: Wireframe components (slots/props), Template Variables (tokens), CSS classes (stateful classes), Component config (props).
  • Inspect the running UI in DevTools (shadowDom={false}) to see the real elements, classes, and structure Velt rendered.
  • Isolate: reproduce the one surface in a minimal setup with default everything, then add your customization back piece by piece.
  • Still nothing fixes it? Decide whether it’s even fixable: SDK gaps and blockers rules out the fixable causes and, if none apply, shows how to record a real SDK gap honestly rather than hacking around it.