theme
The theme prop on TaxKitProvider controls how the iframe renders visually. It takes six optional fields:
interface TaxKitTheme {
light?: ThemeContract;
dark?: ThemeContract;
mode?: 'light' | 'dark';
partnerLogo?: string | { light: string; dark: string };
fonts?: PartnerFontDefinition[];
fontStylesheets?: string | string[];
}
The ThemeContract field names (background, foreground, primary, muted / mutedForeground, accent, destructive, border, input, popover / popoverForeground, radius) match the canonical shadcn / Radix token contract. The iframe's UI is built on CoinTracker's @cointracker/base-ui, which is itself a shadcn-patterned library on top of Radix primitives — if you've worked with shadcn before, the semantics are identical. The ct*-prefixed fields are CoinTracker-specific surfaces with no shadcn equivalent; leave them unset for defaults.
Token values are any valid CSS color string (#0052FF, rgb(0, 82, 255), hsl(216 100% 50%), rgba(0, 82, 255, 0.8)). The iframe doesn't validate — an invalid string renders as the browser default.
Fields
theme.lightThemeContractColor and spacing tokens applied when the iframe renders in light mode. See ThemeContract below for the full token list.
theme.darkThemeContractColor and spacing tokens applied when the iframe renders in dark mode.
theme.mode'light' | 'dark'Force light or dark mode. When omitted, the iframe defaults to the user's OS preference (via prefers-color-scheme).
theme.partnerLogostring | { light: string; dark: string }Partner logo shown in the iframe header. Pass a single URL string to use the same image in both modes, or { light, dark } for mode-specific variants. When unset, the SDK falls back to its built-in logo for known partner slugs (coinbase, kraken). See Partner branding below.
theme.fontsPartnerFontDefinition[]Self-hosted @font-face definitions injected into the iframe. Each entry maps to one @font-face rule — use this when the partner brand font isn't bundled with the SDK and you control the source URLs. See Partner branding below.
theme.fontStylesheetsstring | string[]External font stylesheet URL(s) — Google Fonts, Adobe Fonts, Bunny Fonts. Injected as <link rel="stylesheet"> so the provider handles @font-face, unicode-range subsetting, and format negotiation. See Partner branding below.
Example
<TaxKitProvider
fetchAccessToken={fetchAccessToken}
theme={{
mode: 'dark',
light: {
radius: '0.5rem',
spacing: '0.25rem',
fontSans: '"Inter", sans-serif',
background: 'rgb(255, 255, 255)',
foreground: 'rgb(10, 11, 13)',
primary: 'rgb(0, 82, 255)',
// …see ThemeContract for all available tokens
},
dark: {
radius: '0.5rem',
spacing: '0.25rem',
fontSans: '"Inter", sans-serif',
background: 'rgb(10, 11, 13)',
foreground: 'rgb(245, 248, 255)',
primary: 'rgb(55, 115, 245)',
},
}}
>
<YourApp />
</TaxKitProvider>
If your parent re-renders frequently, memoize the theme object (or its light/dark sub-objects) with useMemo — the provider already wraps the contract in useMemo internally, so stable references from your side avoid re-firing the dispatcher's CONFIG effect. The same applies to partnerLogo (when passed as an object), fonts, and fontStylesheets: pass stable references to avoid unnecessary iframe-side <style> / <link> re-injection.
Partner branding
Three optional fields make it possible to brand the iframe with a partner's own logo and fonts — without bundling assets into the SDK.
Logo: partnerLogo
Replaces the SDK's built-in mark in the iframe header. Accepts either a single URL (used in both modes) or a per-mode object:
// Single URL — same image in light and dark
theme={{
partnerLogo: 'https://cdn.your-partner.com/logo.svg',
}}
// Per-mode variants for inverted logos
theme={{
partnerLogo: {
light: 'https://cdn.your-partner.com/logo-dark-on-light.svg',
dark: 'https://cdn.your-partner.com/logo-light-on-dark.svg',
},
}}
- Host your own asset. Point at a CORS-accessible URL on your CDN or origin. Prefer SVG; if you ship PNG, keep it small (≤ 128px square).
- Sizing is locked. The visual size is constrained by the iframe header — oversized images won't break layout — but bandwidth is still on you.
- Alt text is auto-derived from the partner slug (e.g.
"Coinbase logo"). You do not pass it. - Fallback: when unset, the SDK uses its built-in logo for known partner slugs (
coinbase,kraken). New partners that don't supplypartnerLogoget nothing in the header.
Self-hosted fonts: fonts
@font-face definitions for woff2/woff/ttf/otf files you serve from your own CDN. Each entry is injected verbatim, so you control format, weight, style, and font-display.
theme={{
fonts: [
{
family: 'Partner Sans',
src: 'https://cdn.your-partner.com/partner-sans-regular.woff2',
weight: '400',
style: 'normal',
},
{
family: 'Partner Sans',
src: 'https://cdn.your-partner.com/partner-sans-bold.woff2',
weight: '700',
style: 'normal',
},
],
light: { fontSans: '"Partner Sans", sans-serif', /* …other tokens */ },
dark: { fontSans: '"Partner Sans", sans-serif', /* …other tokens */ },
}}
The PartnerFontDefinition shape mirrors the standard CSS @font-face descriptors:
interface PartnerFontDefinition {
family: string;
src: string;
weight?: string;
style?: string;
display?: string;
}
After registering the family, reference it from light.fontSans and dark.fontSans like any other font chain.
External stylesheets: fontStylesheets
For off-the-shelf web fonts (Google Fonts, Adobe Fonts, Bunny Fonts), pass the stylesheet URL(s) directly. The iframe injects each as <link rel="stylesheet">, so the font provider handles @font-face, format negotiation, and unicode-range subsetting:
// Single URL
theme={{
fontStylesheets:
'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap',
light: { fontSans: '"Inter", sans-serif', /* … */ },
dark: { fontSans: '"Inter", sans-serif', /* … */ },
}}
// Multiple URLs
theme={{
fontStylesheets: [
'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap',
'https://use.typekit.net/your-kit-id.css',
],
}}
Which font field do I use?
| Scenario | Use |
|---|---|
You self-host .woff2 files on your CDN | fonts |
| You're loading a Google Font / Adobe Font / Bunny Font | fontStylesheets |
| Mix of both | Both — they're independent |
ThemeContract fields
Every field is optional. Unset tokens fall back to the iframe's defaults.
backgroundstringPage background color.
foregroundstringDefault text color on background.
primarystringBrand color used for primary buttons, focus rings, and emphasis.
secondarystringSecondary surface color (e.g. card backgrounds).
mutedstringMuted surface color for low-emphasis backgrounds.
mutedForegroundstringMuted text color for low-emphasis copy.
accentstringAccent surface color (used for hover/active states on neutral controls).
destructivestringColor for destructive actions and error states.
warningstringColor for warning states.
successstringColor for success states.
borderstringDefault border color.
inputstringBorder color for form inputs.
popoverstringPopover/modal background. Defaults to background when not provided.
popoverForegroundstringPopover/modal text color. Defaults to foreground when not provided.
radiusstringDefault border-radius for components.
buttonRadiusstringButton border-radius. Defaults to the Coinbase pill shape (9999px) when not provided.
cardRadiusstringCard/container border-radius. Defaults to 1rem (16px) when not provided.
spacingstringBase spacing unit.
fontSansstringSans-serif font stack.
ctCardSurfacestringCoinTracker-specific surface token used inside the kit.
ctForegroundstringCoinTracker-specific foreground token.
ctEmphasisstringCoinTracker-specific emphasis token.
ctSecondarystringCoinTracker-specific secondary token.