Theming Guide

What you'll learn

  1. Use the Theme Playground — visually design a theme and copy the integration snippet.
  2. Apply a base theme — switch between light and dark mode, set a primary brand color.
  3. Override individual tokens — fine-tune colors, spacing, border radius, and font sizes.
  4. Update the theme at runtime — react to user preferences or system changes.

Theme Playground

The fastest way to build a theme is the Theme Playground. It gives you a live preview of the embed with your customizations applied in real time.

How it works:

  1. Open the Theme Playground.
  2. Use the sidebar controls to pick an accent color, adjust border radius and spacing scales, switch between light and dark mode, and edit individual color tokens.
  3. The preview panel updates instantly so you can see how your theme looks across every embed state.
  4. When you're happy, copy the integration snippet at the bottom of the sidebar — it contains only the values that differ from the default theme, ready to paste into your code.
📘

Tip

Use the Theme Playground to test your theme before writing any code. It generates a minimal EmbedTheme object that you can drop straight into the SDK setup below.

How theming works

The SDK sends your theme to the embed via postMessage. Inside the embed, a ThemeProvider reads the theme and applies every value as a CSS custom property on the root element. All UI components reference these variables — when a variable changes, the entire embed updates.

You never interact with postMessage directly. The SDK handles it for you. You just pass a theme object.

Basic theming

The simplest theme sets a mode and a primaryColor:

const THEME = {
  mode: 'dark',
  primaryColor: '#e91e63',
};
PropertyTypeDescription
mode'light' | 'dark'Selects the base color palette. Defaults to dark.
primaryColorstringAny valid CSS color (hex, rgb, hsl). Overrides the primary, primaryHover, cta, and ctaHover tokens — each is set to the value you pass.

Setting mode swaps the entire color palette between light and dark presets. Setting primaryColor overrides the four action-color variables so buttons and interactive elements match your brand. These two properties are enough for most integrations. To customize the page background, use colorOverrides.background — see Granular overrides below.

SDK integration

Updating the theme at runtime

You may want to change the theme after the embed is already mounted — for example, when a user toggles dark mode in your app.

CSS variables reference

Every value in the theme object maps to a CSS custom property set on the embed's root element. The tables below list every variable, its default value in each mode, and what it controls.

Colors

VariableLight defaultDark defaultUsed for
--color-primary#3ECF8E#3ECF8EPrimary actions, links
--color-primary-hover#2EBF7E#2EBF7EPrimary hover state
--color-primary-foreground#FFFFFF#0D1117Text on primary backgrounds
--color-secondary#4C526B#9196A5Secondary actions
--color-secondary-hover#383F5A#ADADB9Secondary hover state
--color-background#FFFFFF#0D1117Page background
--color-surface#F6F8FA#161B22Card backgrounds
--color-surface-elevated#FFFFFF#21262DElevated card backgrounds
--color-text#24292F#FFFFFFPrimary text
--color-text-muted#57606A#8B949ESecondary text
--color-text-subtle#6E7681#6E7681Hint and placeholder text
--color-border#D0D7DE#30363DBorders, dividers
--color-border-subtle#D8DEE4#21262DSubtle dividers
--color-error#F2586B#F2586BError text, icons
--color-error-background#fef2f2#450a0aError banner backgrounds
--color-success#52CEA6#52CEA6Success text, icons
--color-success-background#f0fdf4#052e16Success banner backgrounds
--color-warning#ca8a04#eab308Warning text, icons
--color-warning-background#fefce8#422006Warning banner backgrounds
--color-cta#52CEA6#52CEA6Call-to-action button background
--color-cta-hover#A1E6B6#A1E6B6CTA hover state
--color-cta-foreground#0D1117#0D1117Text on CTA buttons
--color-filled#1A2135#1A2135Filled variant button background
--color-filled-hover#2A324A#2A324AFilled button hover state
--color-filled-foreground#FFFFFF#FFFFFFText on filled buttons
--color-danger#F2586B#F2586BDestructive action button background
--color-danger-hover#D94A5C#D94A5CDanger hover state
--color-danger-foreground#FFFFFF#FFFFFFText on danger buttons

Spacing

VariableDefaultUsed for
--spacing-xs4pxTight gaps, inline padding
--spacing-sm8pxSmall gaps between related elements
--spacing-md16pxStandard padding, section gaps
--spacing-lg24pxCard padding, group spacing
--spacing-xl32pxSection margins, large gaps

Border radius

VariableDefaultUsed for
--radius-sm4pxInputs, small elements
--radius-md8pxButtons, badges
--radius-lg12pxCards, modals
--radius-full9999pxPills, avatars

Font size

VariableDefaultUsed for
--font-size-xs0.75remCaptions, fine print
--font-size-sm0.875remSecondary text, labels
--font-size-md1remBody text
--font-size-lg1.125remSubheadings
--font-size-xl1.25remHeadings

Font family

VariableDefault
--font-sans"GT America", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif
--font-mono"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace
📘

Note

Font family is not currently overridable via ThemePayload. "GT America" is the ProphetX brand font; the system fallbacks render if it's unavailable.

Granular overrides

For full control beyond mode and primaryColor, use the override properties. Each one accepts a partial object — you only need to include the tokens you want to change. Unspecified tokens keep their default values for the selected mode.

colorOverrides

Override any individual color token. Useful when primaryColor isn't enough — for example, matching your brand's error color or surface tones.

const THEME: EmbedTheme = {
  mode: "light",
  primaryColor: "#7c3aed",
  colorOverrides: {
    surface: "#faf5ff",
    surfaceElevated: "#f3e8ff",
    border: "#e9d5ff",
    borderSubtle: "#f3e8ff",
    cta: "#7c3aed",
    ctaHover: "#6d28d9",
    ctaForeground: "#ffffff",
    success: "#059669",
    successBackground: "#ecfdf5",
  },
};

Available keys:

KeyMaps to CSS variable
primary--color-primary
primaryHover--color-primary-hover
primaryForeground--color-primary-foreground
secondary--color-secondary
secondaryHover--color-secondary-hover
background--color-background
surface--color-surface
surfaceElevated--color-surface-elevated
text--color-text
textMuted--color-text-muted
textSubtle--color-text-subtle
border--color-border
borderSubtle--color-border-subtle
error--color-error
errorBackground--color-error-background
success--color-success
successBackground--color-success-background
warning--color-warning
warningBackground--color-warning-background
cta--color-cta
ctaHover--color-cta-hover
ctaForeground--color-cta-foreground
filled--color-filled
filledHover--color-filled-hover
filledForeground--color-filled-foreground
danger--color-danger
dangerHover--color-danger-hover
dangerForeground--color-danger-foreground

spacingOverrides

Adjust the spacing scale to match your design system. Values are CSS length strings.

const THEME: EmbedTheme = {
  mode: "light",
  spacingOverrides: {
    xs: "0.125rem",
    sm: "0.375rem",
    md: "0.75rem",
    lg: "1.25rem",
    xl: "1.75rem",
  },
};
KeyMaps to CSS variableDefault
xs--spacing-xs4px
sm--spacing-sm8px
md--spacing-md16px
lg--spacing-lg24px
xl--spacing-xl32px

radiusOverrides

Control how rounded elements appear. Set full to a smaller value for less pill-shaped buttons, or increase sm through lg for a softer feel.

const THEME: EmbedTheme = {
  mode: "light",
  radiusOverrides: {
    sm: "0.5rem",
    md: "0.75rem",
    lg: "1rem",
  },
};
KeyMaps to CSS variableDefault
sm--radius-sm4px
md--radius-md8px
lg--radius-lg12px
full--radius-full9999px

fontSizeOverrides

Scale typography up or down. Useful if your app uses a different base font size.

const THEME: EmbedTheme = {
  mode: "light",
  fontSizeOverrides: {
    xs: "0.625rem",
    sm: "0.75rem",
    md: "0.875rem",
    lg: "1rem",
    xl: "1.125rem",
  },
};
KeyMaps to CSS variableDefault
xs--font-size-xs0.75rem
sm--font-size-sm0.875rem
md--font-size-md1rem
lg--font-size-lg1.125rem
xl--font-size-xl1.25rem

Full example

Here's a complete theme that combines mode, primary color, and granular overrides — the kind of object the Theme Playground generates for you:

ThemePayload reference

The complete type accepted by the SDK's theme prop and updateTheme():

type ThemePayload = {
  mode?: 'light' | 'dark';
  primaryColor?: string;
  colorOverrides?: Partial<{
    primary: string;
    primaryHover: string;
    primaryForeground: string;
    secondary: string;
    secondaryHover: string;
    background: string;
    surface: string;
    surfaceElevated: string;
    text: string;
    textMuted: string;
    textSubtle: string;
    border: string;
    borderSubtle: string;
    error: string;
    errorBackground: string;
    success: string;
    successBackground: string;
    warning: string;
    warningBackground: string;
    cta: string;
    ctaHover: string;
    ctaForeground: string;
    filled: string;
    filledHover: string;
    filledForeground: string;
    danger: string;
    dangerHover: string;
    dangerForeground: string;
  }>;
  spacingOverrides?: Partial<{
    xs: string;
    sm: string;
    md: string;
    lg: string;
    xl: string;
  }>;
  radiusOverrides?: Partial<{
    sm: string;
    md: string;
    lg: string;
    full: string;
  }>;
  fontSizeOverrides?: Partial<{
    xs: string;
    sm: string;
    md: string;
    lg: string;
    xl: string;
  }>;
};

All properties are optional. An empty object {} applies the default light theme with no overrides.

Edge cases

  • Multiple theme updates: Each theme message fully replaces all CSS variables. There is no incremental merge — if you send { mode: 'dark' } followed by { primaryColor: '#e91e63' }, the second message uses the light theme (default) with only the primary color changed. Always send the complete theme you want applied.
  • Invalid CSS color values: The embed silently ignores invalid color strings. No error is thrown, but the variable won't update — the previous value remains.
  • Order of application: mode selects the base palette first, then primaryColor overrides the four action tokens, then colorOverrides / spacingOverrides / radiusOverrides / fontSizeOverrides are applied on top.

Next steps