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

# Cross-cutting concerns: a11y, i18n, RTL, responsive, testing

> Handle accessibility, localization, RTL, responsive behavior, and testing across Velt customizations.

<Note>
  This is the canonical public docs page for cross-cutting customization concerns. The guide repo calls this topic `cross-cutting`; the docs keep the existing `/ui-customization/localisation` route and redirect `/ui-customization/cross-cutting` here.
</Note>

These apply to **every** approach and feature. Handle them as you build, not after. (The short version lives in [`Setup`](/ui-customization/setup#6-crosscutting-concerns-a11y-i18n-rtl-responsive-testing); this is the deep version.)

***

## Accessibility (a11y)

**What Velt gives you for free, and when you keep it:**

* **Velt's default UI and its slot components** ship with roles, labels, keyboard handling, and focus management.
* **Primitives** render Velt's components, so they **keep** that a11y. Wrapping a primitive in your own UI library is fine: the Velt part stays accessible.
* **Wireframes**: Velt's behavior **and a11y** live in the `Velt…Wireframe.X` **slot components**: keep using them for anything interactive (buttons, inputs, dropdowns). The custom markup *you* add around slots is **yours to make accessible.**
* **Headless**: you own 100% of the a11y: there's no Velt UI to inherit from.

**Your checklist when wireframing or going headless:**

* Use semantic elements (`<button>`, `<nav>`, `<ul>`) and add `aria-*`/`role`/`aria-label` where your markup needs them.
* Preserve a sensible **focus order** and visible **focus styles** (`:focus-visible`). Don't `outline: none` without a replacement.
* Keep interactive behavior in Velt slot components: a custom `<div onClick>` in a wireframe doesn't even run (R4), and a bare div isn't keyboard-accessible anyway.
* Don't rely on **color alone** for state (resolved/unread/priority): pair it with an icon/label.
* When you override colors via `--velt-*`, keep **contrast** at WCAG AA (4.5:1 text). This is easy to break with brand palettes: check both light and dark.
* Respect `prefers-reduced-motion` in any custom transitions you add (e.g. hover-reveal).

**Verify:** keyboard-only navigation through the whole surface; a screen reader pass (VoiceOver / NVDA); zoom to 200%.

***

## i18n / localization

Three levers, in order of power:

1. **Override Velt's built-in strings / add languages**: the strongest lever:
   ```tsx theme={null}
   const { client } = useVeltClient();
   client.setTranslations({
     en: { /* "<string key>": "Your text" */ },
     fr: { /* … */ },
   });
   client.setLanguage("fr");   // switch the active language
   ```
   `setTranslations` takes `{ [language]: { [key]: value } }`: use it to **reword or translate Velt's own UI text**, not just translate. `setLanguage` switches the active language at runtime.
2. **Placeholder props**: composer text: `commentPlaceholder`, `replyPlaceholder`, `editPlaceholder`, `editCommentPlaceholder`, `editReplyPlaceholder` (and the slot-level `placeholder` props). Pass already-translated values.
3. **Your own text**: anything in your wireframe markup or headless components is yours: render it through your app's i18n library.

Notes: dates/relative times render in Velt's UI; if you show your own timestamps (headless), localize them yourself. Combine i18n with RTL (below) for right-to-left languages.

***

## RTL (right-to-left)

* Set **`dir="rtl"`** on the container that wraps your Velt UI; Velt's UI inherits direction from the DOM.
* In **your own** CSS overrides and wireframe markup, prefer **logical properties**: `margin-inline-start`, `padding-inline`, `inset-inline`: instead of hard `left`/`right`, so they mirror automatically.
* **Mirror directional glyphs** (chevrons, arrows, "reply" icons): flip them with `transform: scaleX(-1)` under `[dir="rtl"]` if they're your icons.
* Check anything **absolutely positioned** (pins, dialogs, dropdown popovers) and your `position: relative` wrappers: verify they anchor on the correct side.
* **Verify** the whole surface in an RTL language; fix mirroring in your CSS, never by hacking Velt internals (R0).

***

## Responsive / mobile

* **Use the layout props first** (cheapest): `filterPanelLayout="bottomSheet"` and `filterOptionLayout` on the sidebar, `panelOpenMode` on notifications, the dialog's bottom-sheet mode, `embedMode`/`floatingMode`/`position`. See [`Component config`](/ui-customization/reference/component-config).
* **Your media queries** apply to your wrappers and your wireframe markup. Velt also flips some internal layouts at mobile breakpoints on its own.
* **Touch targets** ≥ \~44px. Important for any custom buttons you place in wireframe slots.
* **Hover-reveal caveat:** the "show actions on hover" recipe ([`Patterns and tips`](/ui-customization/patterns-and-tips)) has no hover on touch. Velt already force-shows per-comment actions on mobile widths; if you build your own hover-reveal, add a tap/always-visible fallback under a mobile media query.
* Test the scroll/height chain (R14) at mobile sizes too: collapsed viewports expose missing `min-height:0` links.

***

## Testing / verifying a customization

<Note>
  For the full **definition of "done"**: driving each surface's states, confirming Velt's behavior is intact, the static rules scan, and the PASS/PARTIAL/FAIL/BLOCKED verdict: see [`Verifying a customization`](/ui-customization/verifying-a-customization). The checklist below is the **cross-cutting** slice of that flow (a11y/dark/RTL/responsive), applied to every surface with custom markup.
</Note>

**Per-surface manual checklist** (run after customizing each surface):

* States: **empty**, **loading/skeleton**, **unread**, **resolved**, **private**, **filtered-to-zero**, long content (truncation).
* **Dark mode** on/off; **RTL** on/off; **mobile** width.
* **Keyboard** navigation + visible focus; quick **screen-reader** pass.
* **Scroll** actually works (R14); nothing overflows or clips.
* **Compare against default**: temporarily remove your customization to confirm a problem is yours vs Velt's.

**Automated:**

* Assert on Velt's **stateful classes** from [`CSS classes`](/ui-customization/reference/css-classes): e.g. expect `.velt-comment-pin-unread-comment` present/absent.
* Read live data via [`Hooks`](/ui-customization/reference/hooks) in component tests: e.g. assert `useUnreadCommentAnnotationCountOnCurrentDocument()?.count`.
* Put **`data-testid`** on **your own** wrapper/markup (not on Velt internals, whose class/structure can change between versions) and target those in e2e.
* **Visual regression** snapshots per surface × (light/dark) × (LTR/RTL) catch CSS-override drift after SDK upgrades: the main risk for class-based overrides.

<Tip>
  After every SDK upgrade, re-run the visual and accessibility checks. Variable-based theming is upgrade-safe, but **class/selector overrides** and wireframe slot names are the most drift-prone pieces.
</Tip>
