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

# CSS

> Theme Velt UI with CSS variables, dark mode tokens, and supported class overrides.

**What it is:** change Velt's look: colors, spacing, fonts, radius, shadows: without touching its structure or behavior. The lowest-effort, most upgrade-safe layer.

**Use it when:** your design is Velt's default UI in different colors/spacing/typography. (Decision tree Q1.)

**Don't use it when:** you need to reorder, add, remove, or relayout parts. Use [wireframes](/ui-customization/layout) for that. And don't use `display:none` to hide features; toggle them with a prop on the [primitive](/ui-customization/primitives) instead.

***

## The model

Velt exposes a large set of **CSS custom properties** (variables), all prefixed `--velt-…`. You override them in your own stylesheet. Velt reads them at render time, so your values flow through its whole UI: including (for variables) inside the shadow DOM.

There are two families:

* **Modern tokens**: `--velt-light-mode-*`, `--velt-dark-mode-*`, `--velt-spacing-*`, `--velt-border-radius-*`, `--velt-font-size-*`, plus z-index tokens. Use these.
* **Legacy tokens**: `--legacy-velt-*` (older components still read some of these). Only touch them if a specific older surface needs it.

Full list: [`CSS variables`](/ui-customization/reference/css-variables).

## Steps

### Step 1: Make sure your selector CSS can reach Velt

CSS **variables** cross the shadow boundary (so **Step 2 variable theming works no matter what**), but **class/element selectors** do not reach inside a shadow DOM. If you'll use any selector-based CSS (Step 5) or styled wireframes, pick **one** of these two supported approaches:

**Option A: turn shadow DOM off** (simplest; your normal stylesheet then reaches the elements):

```tsx theme={null}
<VeltComments shadowDom={false} />
<VeltCommentsSidebar shadowDom={false} />
```

**Option B: keep shadow DOM on, and inject your CSS into the shadow root** with the client's `injectCustomCss` API. Use this when you want to keep Velt's style isolation (so Velt's CSS can't leak into your app and vice-versa) but still style inside it:

```tsx theme={null}
const { client } = useVeltClient();
client.injectCustomCss({ type: "styles", value: `
  .velt-comment-dialog-composer { border-radius: 10px !important; }
` });
// or load an external stylesheet into the shadow root:
client.injectCustomCss({ type: "link", value: "https://yourcdn.com/velt-overrides.css" });
```

`injectCustomCss` pushes your CSS **into Velt's shadow root**, so selectors match there. `type: "styles"` = a raw CSS string; `type: "link"` = a stylesheet URL.

Pick A *or* B per project: don't do both for the same surface. (See [`Setup`](/ui-customization/setup#2-the-shadowdom-rule-read-this-before-any-css-or-wireframe-work).)

#### Shadow DOM & wireframes (root vs nested)

**Verified in-browser.** When you customize with **wireframes**, whether you still need `shadowDom={false}` depends on *which* wireframe you registered:

* **You registered the component's ROOT wireframe** (e.g. `VeltCommentDialogWireframe` / `velt-comment-dialog-wireframe`): Velt **auto-removes that component's own shadow DOM**, so it renders in **light DOM** and your normal class CSS reaches it: **no `shadowDom={false}` needed** for that component.
* **You registered only a NESTED / leaf wireframe** (e.g. just the `ThreadCard`, with no root dialog wireframe): shadow DOM is **NOT** auto-removed. Your layout markup applies, but **class CSS won't reach inside**, so the look may change without your styles landing. For this case you **must** set `shadowDom={false}` (or the per-surface flag / `injectCustomCss`) explicitly.
* **Either way, inline `style=""`** on your wireframe markup always works (it survives the clone and lives in whatever DOM the slot renders into).
* **Nesting caveat:** a root-wireframed component that renders *inside another* shadow-DOM component (e.g. the dialog shown inside the sidebar with the sidebar's default shadow on) still sits in **that outer** component's shadow root: turn the outer component's shadow off too if you need class CSS there.

<Tip>
  Rule of thumb: **root wireframe → class CSS works (shadow auto-off); leaf-only wireframe → set `shadowDom={false}` yourself; inline styles always work.**
</Tip>

### Step 2: Override variables at `:root`

Put all Velt CSS in one stylesheet. Override the tokens you care about:

```css theme={null}
/* velt.css: loaded once */
:root {
  /* Brand accent used across comment UI (buttons, active states, links) */
  --velt-light-mode-accent: #FF6B35;
  --velt-light-mode-accent-hover: #E55A29;

  /* Surfaces & text */
  --velt-light-mode-background-0: #FFFFFF;   /* primary surface */
  --velt-light-mode-text-0: #0A0A0A;         /* primary text */

  /* Shape & rhythm */
  --velt-border-radius-md: 10px;
  --velt-spacing-md: 14px;
  --velt-font-size-sm: 13px;          /* overriding the 14px default */
}
```

These names are real and exhaustive: see [`CSS variables`](/ui-customization/reference/css-variables). **Never invent a token name.**

### Step 3: Support dark mode

Velt switches modes via the `data-velt-theme="dark"` attribute on the document root. Override the dark tokens under that selector:

```css theme={null}
:root[data-velt-theme="dark"] {
  --velt-dark-mode-accent: #FF8A5C;
  --velt-dark-mode-background-0: #0F0F0F;
  --velt-dark-mode-text-0: #FFFFFF;
}
```

You supply the dark values; Velt sets the `data-velt-theme="dark"` attribute when dark mode is on. **To toggle dark mode**, use any of:

* the **`darkMode` prop** on a component: `<VeltComments darkMode={isDark} />` (also `dialogDarkMode`, `pinDarkMode`, … for finer control);
* the **client API**: `const { client } = useVeltClient(); client.setDarkMode(true)` (app-wide);
* **follow the OS preference**: wire your own `prefers-color-scheme` media query to `setDarkMode`.

So: **you decide *when* dark mode is on (prop / `setDarkMode` / OS), and you supply the dark token *values* under `[data-velt-theme="dark"]`.**

### Step 4: Change the default font

Velt reads one global font token, `--velt-default-font-family` (default `sans-serif`). Override it at `:root` and every Velt surface picks it up: no per-component work:

```css theme={null}
:root {
  --velt-default-font-family: "Inter", "Helvetica Neue", Arial, sans-serif;
}
```

(There are no global line-height or font-weight tokens: those are per-component. The `--velt-font-size-*` scale can be overridden the same way.)

### Step 5: Override specific elements by class (always with `!important`)

For anything variables don't cover, target Velt's classes directly. **Velt injects its own styles at runtime with high specificity, so your overrides must use `!important` to win.** Treat this as the rule for class-based Velt CSS, not a hack.

**The workflow (do this for any element you want to restyle):**

1. Run the app with `shadowDom={false}` and **inspect the element** in DevTools.
2. Read the classes on it: Velt applies dual names: a short legacy class (e.g. `selected`) and a BEM `velt-*` class (e.g. `velt-comment-dialog--selected`). **Prefer the `velt-*` class.**
3. Write a rule for that class, ending each declaration with `!important`:

```css theme={null}
/* identified by inspecting the composer's send button */
.velt-composer--submit-button {
  background: #3d5afe !important;
  border-radius: 6px !important;
  color: #fff !important;
}
```

<Tip>
  See [`CSS classes`](/ui-customization/reference/css-classes) for the catalog of structural and **stateful** classes (unread, resolved, selected, has-reactions, hover, filter-applied, and more) you can target. Class names are an implementation detail and can shift between versions, so prefer `--velt-*` variables where one exists. Use `!important` class overrides for the rest, and re-check them on upgrade.
</Tip>

## What it can and can't do

| ✅ CSS can                              | ❌ CSS cannot                                  |
| -------------------------------------- | --------------------------------------------- |
| Recolor everything (light + dark)      | Reorder or restructure the UI                 |
| Change spacing, radius, fonts, shadows | Add/remove UI parts (use a prop or wireframe) |
| Theme to match a brand                 | Insert your own markup between Velt's pieces  |
| Adjust z-index layering                | Change behavior                               |

If you're writing `display:none` to remove parts, or wishing you could move a button, you've hit CSS's ceiling: escalate to [wireframes](/ui-customization/layout) (restructure) or [primitives](/ui-customization/primitives) (toggle features / compose).

## Checklist

* [ ] `shadowDom={false}` on customized components.
* [ ] All Velt CSS in **one** stylesheet.
* [ ] Only `--velt-*` / `--legacy-velt-*` names that exist in [`CSS variables`](/ui-customization/reference/css-variables).
* [ ] Dark values under `:root[data-velt-theme="dark"]`.
* [ ] No `display:none` hacks to remove features (toggle with a prop instead).
