Styling & Customization
Customize the Inflow card payment form with two recommended APIs:
appearance— theme tokens (colors, radii, fonts). Defaults are light; you drive dark (or any theme) by passing the variables you want.options— layout, width, card / wallet button labels and wallet button color (wallets.buttonTheme), placeholders, and success UI
Legacy style and top-level copy props still work, but prefer appearance and options for new integrations.
Quick example
appearance: {
// fonts is optional. When set, cssSrc must be a Google Fonts URL
// (fonts.googleapis.com / fonts.google.com). Built-in fonts like Inter
// load from fontFamily alone — no fonts entry needed.
fonts: [
{
cssSrc:
'https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap',
},
],
variables: {
fontFamily: 'Lato, system-ui, sans-serif',
primaryColor: '#0070F3',
buttonBackgroundColor: '#0070F3',
buttonTextColor: '#FFFFFF',
buttonBorderRadius: '8px',
},
},
options: {
paymentMethodLayout: 'horizontalSelector',
paymentMethodOrder: ['apple_pay', 'google_pay', 'card'],
cardFieldLayout: 'compact',
fillParent: true,
buttonText: 'Pay €49.99',
wallets: {
buttonText: {
applePay: 'Pay with Apple Pay',
googlePay: 'Pay with Google Pay',
},
// buttonTheme: 'white', // default is black — set 'white' for dark surfaces
},
cardForm: {
placeholders: {
cardNumber: 'Card number',
expiry: 'MM / YY',
cvc: 'CVC',
},
},
showDefaultSuccessUI: true,
}Precedence
- Theme: if
appearanceis set, it is used; otherwise legacystyleis applied. - Width:
options.fillParentif set; otherwisestyle.fillParent. - Copy / success UI: values under
optionswin over deprecated top-level fields.
Appearance
Use appearance to theme the checkout form. Variables map to CSS custom properties inside the iframe.
appearance: {
// fonts is optional. When set, cssSrc must be a Google Fonts URL
// (fonts.googleapis.com / fonts.google.com). Built-in fonts like Inter
// load from fontFamily alone — no fonts entry needed.
fonts: [
{
cssSrc:
'https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap',
},
],
variables: {
fontFamily: 'Lato, system-ui, sans-serif',
formBackgroundColor: 'transparent',
backgroundColor: '#ffffff',
textColor: '#111111',
textSecondaryColor: '#6b7280',
placeholderColor: '#9ca3af',
primaryColor: '#111111',
primaryTextColor: '#ffffff',
layoutBorderColor: '#d8d8d8',
inputBorderColor: '#e5e5e5',
inputFocusBorderColor: '#111111',
layoutBorderRadius: '12px',
inputBorderRadius: '8px',
buttonBorderRadius: '8px',
dangerColor: '#ef4444',
dangerBackgroundColor: '#fee2e2',
successColor: '#ffffff',
successBackgroundColor: '#22c55e',
buttonBackgroundColor: '#111111',
buttonTextColor: '#ffffff',
loaderColor: '#e8e8e8',
// Special-case only — see table below:
// iframeBackgroundColor: '#ffffff',
},
}appearance.variables
appearance.variables| Variable | Purpose |
|---|---|
fontFamily | CSS font stack for the form, including wallet button labels. Known Google Fonts in the primary slot are auto-loaded |
formBackgroundColor | Checkout form box background. Default is transparent so the parent page shows through |
iframeBackgroundColor | Special case. Overrides the iframe document (html / body) background. Omit by default; use only when the iframe background does not match the page and formBackgroundColor alone is not enough |
backgroundColor | Input / panel surface background |
textColor | Primary text |
textSecondaryColor | Secondary / muted text (labels, disclaimer, helpers) |
placeholderColor | Input placeholders |
primaryColor | Brand / selection accent |
primaryTextColor | Text and icons on primary-filled surfaces |
layoutBorderColor | Payment-method layout and divider borders |
inputBorderColor | Card input borders |
inputFocusBorderColor | Focused input borders |
layoutBorderRadius | Layout chrome radius |
inputBorderRadius | Input radius |
buttonBorderRadius | Pay / wallet button radius (shared; see Wallet buttons) |
dangerColor | Error text / field errors |
dangerBackgroundColor | Error banner background |
successColor | Success accent |
successBackgroundColor | Success fill surfaces |
buttonBackgroundColor | Card pay button background (falls back to primaryColor when omitted). Does not apply to wallet buttons |
buttonTextColor | Card pay button label color. Does not apply to wallet buttons |
loaderColor | Skeleton loader shimmer base color on the parent page while the iframe loads. Any CSS color (hex, rgb, named like red, hsl, …). Default light grey; the highlight stop is lightened from this |
appearance.fonts
appearance.fontsOptional Google Fonts stylesheets for fonts outside the SDK auto-load list.
These are auto-loaded from fontFamily alone (no fonts entry needed):
DM Sans, Inter, Poppins, Nunito, Work Sans, Manrope, Rubik, Karla, Figtree, Outfit, Space Grotesk, Urbanist.
For any other Google Font, pass a stylesheet URL. Only https://fonts.googleapis.com and https://fonts.google.com HTTPS URLs are accepted.
appearance: {
fonts: [
{
cssSrc:
'https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap',
},
],
variables: {
fontFamily: 'Lato, system-ui, sans-serif',
},
}Dark mode
Current SDK builds keep light CSS token defaults in the iframe. There is no automatic OS dark-mode flip when you use appearance — appearance.variables is the single source of truth.
appearance also has no built-in dark block (unlike legacy style.dark).
To support dark mode (or any custom theme), detect it in your app however you prefer (system preference, class toggle, theme provider, etc.), then provide the matching appearance.variables based on your dark mode flag and set options.wallets.buttonTheme so wallet buttons match the surface (e.g. "white" on dark backgrounds).
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
appearance: {
variables: isDark
? {
backgroundColor: '#1A1A1A',
textColor: '#FFFFFF',
textSecondaryColor: '#959499',
placeholderColor: '#959499',
primaryColor: '#FFFFFF',
primaryTextColor: '#111111',
buttonBackgroundColor: '#FFFFFF',
buttonTextColor: '#111111',
layoutBorderColor: '#333333',
inputBorderColor: '#333333',
loaderColor: '#2d2d2d',
}
: {
backgroundColor: '#FFFFFF',
textColor: '#1A1A1A',
primaryColor: '#0070F3',
buttonBackgroundColor: '#0070F3',
buttonTextColor: '#FFFFFF',
loaderColor: '#e8e8e8',
},
},
options: {
wallets: {
// Match the checkout surface — white wallets on dark, black on light
buttonTheme: isDark ? 'white' : 'black',
},
},Options
Use options for layout and non-theme configuration.
options: {
paymentMethodLayout: 'stacked', // 'stacked' | 'verticalSelector' | 'horizontalSelector'
paymentMethodOrder: ['apple_pay', 'google_pay', 'card'],
cardFieldLayout: 'compact', // 'compact' | 'split'
fillParent: true,
buttonText: 'Pay now',
wallets: {
buttonText: {
applePay: 'Pay with Apple Pay',
googlePay: 'Pay with Google Pay',
},
// buttonTheme: 'white', // default is black — set 'white' for dark surfaces
},
cardForm: {
placeholders: {
cardNumber: 'Card number',
expiry: 'MM / YY',
cvc: 'CVC',
},
},
showDefaultSuccessUI: true,
}| Option | Default | Description |
|---|---|---|
paymentMethodLayout | stacked | stacked (wallets on top, card always visible), verticalSelector (vertical selectable list), or horizontalSelector (horizontal selectable tabs) |
paymentMethodOrder | card, then wallets | Display order and default selection for verticalSelector and horizontalSelector only. Values: card, apple_pay, google_pay. First available method is shown first and selected; unavailable entries are skipped. Does not change stacked layout behavior |
cardFieldLayout | compact | compact (grouped fields) or split (number alone; expiry + CVC on a second row) |
fillParent | false | When true, host iframe and form use 100% width |
buttonText | "Complete Payment" | Card pay button label (does not apply to wallet buttons) |
wallets.buttonText.applePay | locale "Pay" | Apple Pay button label (translated when omitted; overrides are used as-is) |
wallets.buttonText.googlePay | locale "Pay" | Google Pay button label (translated when omitted; overrides are used as-is) |
wallets.buttonTheme | "black" | Wallet button color — "black" or "white" to match your checkout surface. Defaults to black when unset; see Wallet buttons |
cardForm.placeholders | — | Card number / expiry / CVC placeholders |
showDefaultSuccessUI | true | Show the built-in success screen after payment |
Wallet buttons
Apple Pay and Google Pay are configured under options.wallets. Appearance color tokens do not theme wallet button fill/label colors — use wallets.buttonTheme for that.
What appearance applies to wallet buttons
Only these Appearance variables affect wallet buttons:
appearance.variables.fontFamily— wallet button label font (shared with the rest of the form)appearance.variables.buttonBorderRadius— corner radius (shared with the card pay button)
Every other Appearance property — including colors such as buttonBackgroundColor, buttonTextColor, primaryColor, borders, and the rest of the variables table — does not apply to wallet buttons.
What you configure under options.wallets
| Field | Purpose |
|---|---|
buttonText.applePay / buttonText.googlePay | Wallet button labels. If omitted, the iframe uses the localized default for "Pay". Merchant-provided strings are not translated. |
buttonTheme | Wallet button color for your checkout design. Set "black" or "white" to match the surface the buttons sit on (e.g. "white" on dark backgrounds). Defaults to black when unset. |
buttonTheme | Background | Text |
|---|---|---|
black (default) | Black | White |
white | White | Black |
Wallet buttons use black or white only; you cannot set custom brand colors on them via Appearance.
options: {
buttonText: 'Start Trial', // card CTA only
wallets: {
buttonText: {
applePay: 'Pay $0.50 & Start Trial',
googlePay: 'Pay with Google Pay',
},
buttonTheme: 'white',
},
},
appearance: {
variables: {
fontFamily: 'Lato, system-ui, sans-serif', // applies to wallet labels
buttonBorderRadius: '8px', // applies to card + wallet buttons
buttonBackgroundColor: '#adffd2', // card pay button only — not wallets
buttonTextColor: '#000000', // card pay button only — not wallets
},
},Payment method order
Applies to selector layouts (verticalSelector / horizontalSelector):
options: {
paymentMethodLayout: 'horizontalSelector',
paymentMethodOrder: ['apple_pay', 'google_pay', 'card'],
}If Apple Pay is unavailable, Google Pay is selected when available; otherwise Card. Remaining enabled methods that were not listed are appended after your order.
Legacy styling (style)
style)The style object is deprecated but still fully supported when appearance is not provided.
style: {
fontFamily: 'Inter',
fillParent: true,
formBackgroundColor: '#211e19',
inputContainer: {
backgroundColor: '#F5F5F5',
borderRadius: '8px',
borderEnabled: true,
borderColor: '#E0E0E0',
},
input: {
textColor: '#1A1A1A',
placeholderColor: '#999999',
backgroundColor: 'transparent',
},
button: {
backgroundColor: '#0070F3',
textColor: '#FFFFFF',
borderRadius: '8px',
fontSize: '16px',
fontWeight: 600,
hover: {
backgroundColor: '#0051CC',
},
disabled: {
opacity: 0.5,
},
},
successUI: {
backgroundColor: '#F5F5F5',
primaryTextColor: '#1A1A1A',
secondaryTextColor: '#999999',
},
dark: {
inputContainer: {
backgroundColor: '#1A1A1A',
borderColor: '#333333',
},
input: {
textColor: '#FFFFFF',
placeholderColor: '#959499',
},
button: {
backgroundColor: '#0066CC',
},
successUI: {
backgroundColor: '#1A1A1A',
primaryTextColor: '#FFFFFF',
secondaryTextColor: '#959499',
},
},
}Supported legacy style fields: fontFamily, fillParent, formBackgroundColor, inputContainer, input, button (including hover / disabled / loaderColor), successUI, generalError, disclaimerColor, fieldErrorColor, dark.
Legacy → recommended
| Legacy field | Recommended replacement |
|---|---|
style | appearance.variables |
style.fillParent | options.fillParent |
style.fontFamily | appearance.variables.fontFamily (+ optional appearance.fonts) |
style.dark | No appearance.dark — detect theme in your app and pass matching appearance.variables (plus options.wallets.buttonTheme for wallet colors) |
top-level buttonText | options.buttonText |
top-level placeholders | options.cardForm.placeholders |
top-level showDefaultSuccessUI | options.showDefaultSuccessUI |
Top-level buttonText, placeholders, and showDefaultSuccessUI remain supported for compatibility:
buttonText: 'Pay €49.99',
placeholders: {
cardNumber: '1234 5678 9012 3456',
expiry: 'MM/YY',
cvc: 'CVC',
},Prefer
options.buttonTextandoptions.cardForm.placeholdersfor new integrations.
The styling API may evolve. Refer to the npm package for the full TypeScript types and all available properties.
Updated 18 days ago