Theming Guide
What you'll learn
- Use the Theme Playground — visually design a theme and copy the integration snippet.
- Apply a base theme — switch between light and dark mode, set a primary brand color.
- Override individual tokens — fine-tune colors, spacing, border radius, and font sizes.
- 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:
- Open the Theme Playground.
- 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.
- The preview panel updates instantly so you can see how your theme looks across every embed state.
- 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.
TipUse the Theme Playground to test your theme before writing any code. It generates a minimal
EmbedThemeobject 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',
};| Property | Type | Description |
|---|---|---|
mode | 'light' | 'dark' | Selects the base color palette. Defaults to dark. |
primaryColor | string | Any 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
| Variable | Light default | Dark default | Used for |
|---|---|---|---|
--color-primary | #3ECF8E | #3ECF8E | Primary actions, links |
--color-primary-hover | #2EBF7E | #2EBF7E | Primary hover state |
--color-primary-foreground | #FFFFFF | #0D1117 | Text on primary backgrounds |
--color-secondary | #4C526B | #9196A5 | Secondary actions |
--color-secondary-hover | #383F5A | #ADADB9 | Secondary hover state |
--color-background | #FFFFFF | #0D1117 | Page background |
--color-surface | #F6F8FA | #161B22 | Card backgrounds |
--color-surface-elevated | #FFFFFF | #21262D | Elevated card backgrounds |
--color-text | #24292F | #FFFFFF | Primary text |
--color-text-muted | #57606A | #8B949E | Secondary text |
--color-text-subtle | #6E7681 | #6E7681 | Hint and placeholder text |
--color-border | #D0D7DE | #30363D | Borders, dividers |
--color-border-subtle | #D8DEE4 | #21262D | Subtle dividers |
--color-error | #F2586B | #F2586B | Error text, icons |
--color-error-background | #fef2f2 | #450a0a | Error banner backgrounds |
--color-success | #52CEA6 | #52CEA6 | Success text, icons |
--color-success-background | #f0fdf4 | #052e16 | Success banner backgrounds |
--color-warning | #ca8a04 | #eab308 | Warning text, icons |
--color-warning-background | #fefce8 | #422006 | Warning banner backgrounds |
--color-cta | #52CEA6 | #52CEA6 | Call-to-action button background |
--color-cta-hover | #A1E6B6 | #A1E6B6 | CTA hover state |
--color-cta-foreground | #0D1117 | #0D1117 | Text on CTA buttons |
--color-filled | #1A2135 | #1A2135 | Filled variant button background |
--color-filled-hover | #2A324A | #2A324A | Filled button hover state |
--color-filled-foreground | #FFFFFF | #FFFFFF | Text on filled buttons |
--color-danger | #F2586B | #F2586B | Destructive action button background |
--color-danger-hover | #D94A5C | #D94A5C | Danger hover state |
--color-danger-foreground | #FFFFFF | #FFFFFF | Text on danger buttons |
Spacing
| Variable | Default | Used for |
|---|---|---|
--spacing-xs | 4px | Tight gaps, inline padding |
--spacing-sm | 8px | Small gaps between related elements |
--spacing-md | 16px | Standard padding, section gaps |
--spacing-lg | 24px | Card padding, group spacing |
--spacing-xl | 32px | Section margins, large gaps |
Border radius
| Variable | Default | Used for |
|---|---|---|
--radius-sm | 4px | Inputs, small elements |
--radius-md | 8px | Buttons, badges |
--radius-lg | 12px | Cards, modals |
--radius-full | 9999px | Pills, avatars |
Font size
| Variable | Default | Used for |
|---|---|---|
--font-size-xs | 0.75rem | Captions, fine print |
--font-size-sm | 0.875rem | Secondary text, labels |
--font-size-md | 1rem | Body text |
--font-size-lg | 1.125rem | Subheadings |
--font-size-xl | 1.25rem | Headings |
Font family
| Variable | Default |
|---|---|
--font-sans | "GT America", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif |
--font-mono | "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace |
NoteFont 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
colorOverridesOverride 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:
| Key | Maps 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
spacingOverridesAdjust 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",
},
};| Key | Maps to CSS variable | Default |
|---|---|---|
xs | --spacing-xs | 4px |
sm | --spacing-sm | 8px |
md | --spacing-md | 16px |
lg | --spacing-lg | 24px |
xl | --spacing-xl | 32px |
radiusOverrides
radiusOverridesControl 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",
},
};| Key | Maps to CSS variable | Default |
|---|---|---|
sm | --radius-sm | 4px |
md | --radius-md | 8px |
lg | --radius-lg | 12px |
full | --radius-full | 9999px |
fontSizeOverrides
fontSizeOverridesScale 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",
},
};| Key | Maps to CSS variable | Default |
|---|---|---|
xs | --font-size-xs | 0.75rem |
sm | --font-size-sm | 0.875rem |
md | --font-size-md | 1rem |
lg | --font-size-lg | 1.125rem |
xl | --font-size-xl | 1.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
ThemePayload referenceThe 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:
modeselects the base palette first, thenprimaryColoroverrides the four action tokens, thencolorOverrides/spacingOverrides/radiusOverrides/fontSizeOverridesare applied on top.
Next steps
- Theme Playground — design your theme visually and export the code
- Deposits and Withdrawals — end-to-end integration guide
- postMessage Protocol — low-level event reference, including
PROPHETX_THEME - Error Codes — every error code and how to handle it
Updated 6 days ago
