Decision tree) has told you which layer(s) you’re using.
Start from a working Velt installation. This guide assumes Velt is already installed, the user is already authenticated, and comments, sidebars, or the relevant collaboration surfaces are already rendering. Your customization work is to add wireframes, compose primitives, and add CSS. You do not need to rebuild SDK setup, auth, or documents unless the app is not rendering Velt yet. The one exception is the primitives path: there you fetch data with hooks and loop over it as part of the customization itself. Section 1 is context only; skip to the
shadowDom rule if the app already shows Velt’s default UI.1. What’s already in the project (context: you don’t build this)
The pieces below already exist in the target app. You don’t write them: this section just helps you recognize them so you know the customization will render:Install the SDK
React apps use
@veltdev/react. Vanilla or other framework apps use @veltdev/client; the same <velt-*> custom elements apply.Authenticate the user via an auth provider
Pass an
authProvider to <VeltProvider>. This is the production way to sign a user in: the auth provider carries the user object and a generateToken callback that returns a Velt JWT. The SDK calls it on sign-in and refreshes it automatically on expiry. The token is minted by your backend, which holds your Velt API secret, so users can’t spoof identity.VeltAuthProvider = { user, generateToken?, retryConfig?, options?, onError? }. There’s also a simpler useIdentify() → identify(user) for quick prototyping without tokens, but prefer the auth provider because it’s what production setups and the reference implementations use.2. The shadowDom rule (read this before any CSS or wireframe work)
Velt can render inside a shadow DOM (an isolated DOM bubble). That isolation blocks your stylesheets.
Two cases:
- Variable-only theming (you only override
--velt-*tokens): works regardless of shadow DOM: variables cross the boundary. You don’t strictly need to change anything. - Selector-based CSS (class/element selectors) or styled wireframes: these cannot reach inside the shadow DOM. Two supported options: pick one:
- A. Turn shadow DOM off so your normal stylesheet reaches the elements:
- B. Keep shadow DOM on and inject your CSS into the shadow root (keeps Velt’s style isolation):
- A. Turn shadow DOM off so your normal stylesheet reaches the elements:
--velt-* overrides still apply, but your class-based CSS won’t reach inside, so it looks like “my CSS does nothing.”
Rule of thumb: anything beyond pure variable theming ⇒ shadow DOM off or injectCustomCss. (See CSS and Rules.)
3. Recommended folder structure
This structure keeps your app code, Velt setup, and Velt UI customization cleanly separated. Use it as-is.- One place to look. Anyone (or any tool) finds all customization under
components/velt/ui-customization/. - App UI stays separate from Velt UI: no tangling.
- One stylesheet for all Velt CSS variables/classes, not scattered across components.
- One
<VeltWireframe>root (inVeltCustomization.tsx): required (see below), and easy to find.
4. The structural rules you must follow from day one
These come up in every approach; the full list is inRules. The two that affect setup:
- Use one
<VeltWireframe>in the whole app. It feeds a global registry; extra roots merge first-with-content-wins (order-dependent, conflict-prone). Put one inVeltCustomization.tsx, rendered once near the root. (See R1 inRules.) shadowDom={false}on any component you style. (Section 2.)
5. A complete minimal example
Everything in one place: provider + auth provider → document → a wireframed dialog + themed CSS. This is the smallest setup that renders a customized comment surface.<VeltCommentDialog> primitive, or drop the VeltCustomization entirely and rely on CSS only: the rest of the wiring is identical.
6. Cross-cutting concerns (a11y, i18n, RTL, responsive, testing)
These apply across every approach: handle them as you build, not after. Quick version below; full guidance inCross-cutting concerns.
- Accessibility. Velt’s default UI and its slot components ship with roles/labels/keyboard behavior; primitives keep it. In wireframes, your custom markup is yours to make accessible (add
aria-*/roles/labels, ensure focus order), but always keep theVelt…Wireframe.Xslot components for anything interactive, since they carry both behavior and a11y. Verify with keyboard-only + a screen reader. - i18n / localization. Three levers: (1) override Velt’s built-in strings / add languages with
client.setTranslations({ en: { "<key>": "My text" }, fr: { … } })and switch withclient.setLanguage("fr"); (2) pass translated placeholder props (commentPlaceholder,replyPlaceholder,editPlaceholder, …); (3) for text in your own wireframe markup or headless components, localize it yourself. So you can fully translate or reword Velt’s UI text. - RTL. Set
dir="rtl"on your container; Velt UI inherits direction. Check mirrored layouts on your custom wireframe/CSS (padding/margins, icon direction). If a surface doesn’t mirror cleanly, fix it in your CSS rather than hacking Velt internals (R0). - Responsive / mobile. Use the layout props (
filterPanelLayout="bottomSheet",embedMode, the dialog’s bottom-sheet mode) plus your own CSS media queries on your wrappers/wireframe markup. SeeComponent config. - Testing / verifying a customization. Per surface: compare against Velt’s default (remove your customization); check the empty / loading / unread / resolved states; check dark mode; check keyboard + scroll; resize for mobile. For automated tests, assert on Velt’s stateful classes (
CSS classes) or read data via hooks (Hooks).
7. How to think while customizing
- One feature at a time. Customize the comment dialog fully, verify it, then move to the sidebar. Don’t customize several surfaces half-way.
- Cheapest layer first. CSS → Wireframes → Primitives → Headless. Escalate only when blocked (the decision tree’s escalation notes tell you when).
- Look up, don’t guess. Every CSS variable, wireframe slot, variable token, and hook is listed in
reference/. If it’s not there, it doesn’t exist: don’t invent names. - Verify against the default. When something looks wrong, compare with Velt’s default UI (temporarily remove your customization). It isolates “my styling” from “Velt behavior.”
CSS, Primitives, Wireframes, or Headless. If you’re mixing layers, use Combining approaches.
