---
title: Appearance and language
description: Customize survey colors, typography, interface text, localization and dismissal behavior.
package: "@userreason/js"
version: "0.5.4"
url: https://docs.userreason.com/sdk/presentation/
updated: 2026-10-18
---

# Appearance and language

Survey questions and invitations are managed in the dashboard or survey definition. SDK options control the surrounding interface and its behavior.

## Theme and language

```ts
import UserReason from '@userreason/js';

UserReason.init({
  siteId: 'YOUR_SITE_ID',
  locale: 'nl',
  theme: {
    accent: '#5E6AD2',
    background: '#FFFFFF',
    text: '#171717',
    fontFamily: 'Inter, sans-serif',
  },
  messages: { next: 'Verder', send: 'Versturen' },
  closeOnBackdropClick: true,
});
```

Replace the site ID. Theme values are CSS strings. The widget uses Shadow DOM to isolate its styles from your app.

## Managed translations

For managed surveys, the SDK prefers an explicit `locale`, then the browser's ordered languages, then the survey's default language. Configure the survey's default `language` and its `translations` together. Translations refer to stable question, option, row and field IDs; see [Survey definition](https://docs.userreason.com/prompts/definition/index.md#languages).

The card's own text (buttons, hints, validation) is translated into more than 40 languages. English is part of the SDK; the SDK fetches any other language from the UserReason API when a survey needs it, so languages are added and corrected without an SDK update. A regional language reads the closest translation (`nl-BE` reads Dutch, `zh-TW` Traditional Chinese), and a language without one has English controls. Survey text comes from the translations configured for that survey.

`messages` overrides interface text for all languages. Each value is at most 500 characters. Import the `Messages` type for editor completion:

```ts
import type { Messages } from '@userreason/js';

export const feedbackMessages = {
  next: 'Continue',
  send: 'Send feedback',
  progress: '{current} of {total}',
} satisfies Partial<Messages>;
```

### Message keys

| Area | Keys |
| - | - |
| Navigation and delivery | `close`, `back`, `next`, `send`, `sending`, `retry`, `progress`, `sentNow`, `thankYou`, `received`, `failed`, `responseLimit` |
| Questions and validation | `chooseRating`, `chooseOne`, `chooseAny`, `chooseUpTo`, `chooseExactly`, `chooseRange`, `selected`, `selectedOf`, `maxReached`, `required`, `optional`, `ratingValue`, `yourFeedback`, `placeholder`, `enterFeedback`, `chooseAnswer`, `chooseAtLeast`, `answerOne` |
| Discard confirmation | `discardTitle`, `discardProgress`, `discardText`, `keepEditing`, `discard` |
| Ranking, dates and fields | `rankTop`, `rankHint`, `enterDate`, `notBefore`, `notAfter`, `enterEmail`, `fillIn`, `prefilled`, `tickConsent` |
| Invitation | `start`, `notNow`, `neverAsk`, `aboutMinutes`, `underMinute`, `questionCount`, `startsSurvey`, `you` |

Preserve the relevant placeholders in overrides: `{current}`, `{total}`, `{min}`, `{max}`, `{value}`, `{count}` and `{date}`.

## Dismissal and retries

The survey is nonmodal: the host page remains usable, and automatic display does not steal focus. `closeOnBackdropClick` defaults to false. When enabled, the outside click still reaches your app. Closing with unfinished answers asks for confirmation. A temporary delivery failure keeps the answers available for retry.

When the workspace response allowance is exhausted, the SDK keeps the latest answers visible, explains that they could not be saved, and allows closing the card. It does not offer retry or report a successful submission. The `responseLimit` message falls back to English when the selected translation does not yet include it; use `messages.responseLimit` to provide your own wording.

## Content Security Policy

Allow connections to your configured UserReason API origin in `connect-src`; [voice answers](https://docs.userreason.com/sdk/voice-answers/index.md) use the same origin and need no extra entry, but do need the microphone allowed by your `Permissions-Policy`. Hosted option images and asker photos need their hosts allowed in `img-src`. If your style policy uses nonces, pass the current page's nonce through the `nonce` option. Check the browser console for the specific blocked resource rather than broadly relaxing your policy.
