Skip to content

Theming

Spotlight uses CSS custom properties (--spot-* variables) for all visual styling. Because the SDK renders inside a Shadow DOM, CSS custom properties are the only CSS mechanism that crosses the shadow boundary -- making them the natural theming primitive.

How It Works

  1. All Spotlight component styles reference --spot-* variables exclusively. No raw colour values, no hardcoded fonts.
  2. Theme values are applied as inline styles on the Shadow DOM host element.
  3. CSS custom properties inherit through the Shadow DOM boundary, cascading to all child components.
  4. Switching themes swaps the property values in place -- no page reload, no re-render, approximately 0.5ms for all 34 properties.
document.body
  └── <div id="spotlight-host"
           style="--spot-primary: #4f46e5; --spot-bg: #ffffff; ...">
        └── #shadow-root
              └── components reference var(--spot-primary), var(--spot-bg), etc.

Setting Theme Values

Via init() Options

Pass a flat object of CSS custom property overrides to the theme option:

js
Spotlight.init({
  apiKey: 'spot_live_abc123',
  theme: {
    '--spot-primary': '#FF6B00',
    '--spot-bg': '#fafafa',
    '--spot-radius': '12px',
    '--spot-font-family': '"Inter", system-ui, sans-serif',
  },
});

Values you provide override the tenant defaults from the admin panel. Properties you omit use the admin-configured or built-in defaults.

Via the Admin Panel

The admin panel includes a visual theme builder with:

  • Colour pickers for each property group (primary, background, text, border, accent)
  • Typography controls (font family, size scale, weight scale)
  • Spacing and radius sliders
  • Shadow editor
  • Light/dark toggle with independent editing per variant
  • Live preview panel showing a mock tooltip, modal, and banner
  • "Copy from light" button for dark variant (inverts colours as a starting point)
  • "Reset to defaults" per variant

Changes in the admin panel take effect immediately for all users without requiring a code deploy.

Via the API

bash
PUT /v1/admin/themes/{theme_id}
Content-Type: application/json

{
  "name": "Brand Default",
  "light": {
    "variables": {
      "--spot-primary": "#4f46e5",
      "--spot-bg": "#ffffff",
      "--spot-text": "#1e293b"
    }
  },
  "dark": {
    "variables": {
      "--spot-primary": "#818cf8",
      "--spot-bg": "#1e1e2e",
      "--spot-text": "#cdd6f4"
    }
  }
}

CSS Custom Property Reference

Colours

PropertyDefault (Light)Default (Dark)Description
--spot-primary#4f46e5#818cf8Primary brand colour for buttons, links, accents
--spot-primary-hover#4338ca#6366f1Primary colour on hover
--spot-primary-text#ffffff#ffffffText colour on primary backgrounds
--spot-bg#ffffff#1e1e2eComponent background colour
--spot-bg-secondary#f8fafc#2a2a3cSecondary background (cards, code blocks)
--spot-text#1e293b#cdd6f4Primary text colour
--spot-text-secondary#64748b#a6adc8Secondary/muted text colour
--spot-border#e2e8f0#45475aBorder colour for cards, inputs, dividers
--spot-success#16a34a#a6e3a1Success state colour
--spot-warning#d97706#f9e2afWarning state colour
--spot-error#dc2626#f38ba8Error state colour
--spot-overlay-bgrgba(0, 0, 0, 0.5)rgba(0, 0, 0, 0.7)Backdrop overlay for modals and spotlights

Typography

PropertyDefaultDescription
--spot-font-familysystem-ui, -apple-system, sans-serifBase font family
--spot-font-size-xs0.75remExtra small text (labels, badges)
--spot-font-size-sm0.875remSmall text (secondary content)
--spot-font-size-base1remBase text size
--spot-font-size-lg1.125remLarge text (titles)
--spot-font-size-xl1.5remExtra large text (modal headings)
--spot-font-weight-normal400Normal text weight
--spot-font-weight-medium500Medium text weight
--spot-font-weight-bold600Bold text weight

Spacing

PropertyDefaultDescription
--spot-spacing-xs0.25remExtra small spacing
--spot-spacing-sm0.5remSmall spacing
--spot-spacing-md1remMedium spacing (default padding)
--spot-spacing-lg1.5remLarge spacing

Effects

PropertyDefault (Light)Default (Dark)Description
--spot-shadow0 1px 3px rgba(0,0,0,0.1)0 1px 3px rgba(0,0,0,0.4)Default box shadow
--spot-shadow-lg0 10px 25px rgba(0,0,0,0.1)0 10px 25px rgba(0,0,0,0.5)Large box shadow (modals, dropdowns)
--spot-radius8px8pxDefault border radius
--spot-radius-lg12px12pxLarge border radius (modals, cards)

Component-Specific

PropertyDefault (Light)Default (Dark)Description
--spot-hotspot-color#4f46e5#818cf8Hotspot beacon colour
--spot-hotspot-size24px24pxHotspot beacon size
--spot-progress-bg#e2e8f0#45475aTour progress bar background
--spot-progress-fill#4f46e5#818cf8Tour progress bar fill colour
--spot-z-index999999999999Base z-index for the SDK host element

TIP

Call Spotlight.getThemeVariables() at runtime to get the full list of supported properties with their current values and descriptions.

Dark Mode

Automatic Detection

The SDK listens to window.matchMedia('(prefers-color-scheme: dark)'). When a dark theme variant is configured for your tenant and the user's operating system preference is dark, the SDK automatically applies the dark variant.

js
// Automatic -- SDK detects OS preference
Spotlight.init({
  apiKey: 'spot_live_abc123',
  // No theme needed; the tenant's configured dark variant applies automatically
});

Manual Control

Override automatic detection with setTheme():

js
// Sync with your app's theme toggle
Spotlight.setTheme('dark');
Spotlight.setTheme('light');
js
function ThemeToggle() {
  const [isDark, setIsDark] = useState(false);

  const toggle = () => {
    const next = !isDark;
    setIsDark(next);
    document.documentElement.classList.toggle('dark', next);
    Spotlight.setTheme(next ? 'dark' : 'light');
  };

  return <button onClick={toggle}>{isDark ? 'Light' : 'Dark'}</button>;
}
js
document.getElementById('theme-toggle').addEventListener('click', () => {
  const isDark = document.documentElement.classList.toggle('dark');
  Spotlight.setTheme(isDark ? 'dark' : 'light');
});

Dark Mode Defaults

When no custom dark variant is configured, the SDK uses built-in dark defaults that meet WCAG AA contrast requirements:

Contrast PairRatioWCAG AA Requirement
Text (#cdd6f4) on Background (#1e1e2e)11.5:14.5:1 (passes)
Primary (#818cf8) on Background (#1e1e2e)5.2:14.5:1 (passes)
Secondary text (#a6adc8) on Background (#1e1e2e)7.3:14.5:1 (passes)

Theme Switch Animation

The SDK applies smooth CSS transitions when switching between light and dark variants:

css
:host {
  transition: color 150ms, background-color 150ms, border-color 150ms;
}

Colour properties transition smoothly while layout properties (spacing, radius) change instantly to avoid layout reflow.

Creating Multiple Themes

Your tenant can have multiple named themes. Only one theme is active (flagged as default) at any time.

Common theme patterns:

Theme NameUse Case
Brand DefaultStandard brand colours for everyday use
High ContrastAccessibility-focused with maximum contrast ratios
HolidaySeasonal branding for campaigns
Partner White-LabelCustom branding for partner-facing content

Create and manage themes via the admin panel or the API:

bash
# List all themes
GET /v1/admin/themes

# Create a new theme
POST /v1/admin/themes
{
  "name": "High Contrast",
  "light": {
    "variables": {
      "--spot-primary": "#0000ff",
      "--spot-text": "#000000",
      "--spot-bg": "#ffffff",
      "--spot-border": "#000000"
    }
  }
}

# Set a theme as the default
PUT /v1/admin/themes/{theme_id}
{ "is_default": true }

Advanced: Custom CSS Escape Hatch

If --spot-* properties do not cover your styling needs, inject custom CSS directly into the Shadow DOM:

js
Spotlight.init({
  apiKey: 'spot_live_abc123',
  customCSS: `
    .spot-tooltip {
      backdrop-filter: blur(8px);
    }
    .spot-modal__title {
      background: linear-gradient(135deg, var(--spot-primary), #ff6b6b);
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
    }
    .spot-progress-bar {
      border-radius: 999px;
    }
  `,
});

DANGER

Custom CSS targets internal class names (.spot-tooltip, .spot-modal__title, etc.) that are not a stable API. These class names may change between SDK versions without notice. Prefer --spot-* custom properties for all standard theming. Use customCSS only as a last resort.

Theme Variable Validation

All theme variable names must:

  • Start with --spot- prefix
  • Be recognised by the SDK (unknown variables are silently ignored)

All theme variable values are validated:

  • Colour properties are checked against hex/rgb/hsl formats
  • Unrecognised value formats produce a warning in debug mode but do not break rendering

Each theme variant supports a maximum of 100 custom properties. The typical theme uses 34 properties (the full default set).

Previewing Themes

The admin panel provides a live preview when editing themes. You can also preview a theme without saving it via the API:

bash
POST /v1/admin/themes/preview
{
  "light": {
    "variables": {
      "--spot-primary": "#FF6B00",
      "--spot-radius": "16px"
    }
  }
}

The preview endpoint returns the fully merged theme (your overrides + defaults) without persisting anything.

Spotlight