Vanilla JS

Walk through embedding Checkout Components on a plain HTML page using vanilla JavaScript.

Canonical reference for every styling property exposed by the FastSpring Checkout SDK components: fs-card, fs-email, fs-apple-pay, fs-coupon, fs-pay-button, and fs-disclosures.

For setup and integration, see the Vanilla JS Integration Guide. This document is a lookup reference — code examples here are illustrative, not full integrations.


How styling works

Each component takes an options object with a style key. Inside style, organize overrides by state (default, hover, focus, error, …) and then by style category (card, input, button, …):

sdk.components.create('fs-card', {
  style: {
    state: {
      default: {
        card: {
          backgroundColor: '#ffffff',
          borderRadius: '12px',
        },
        input: {
          borderColor: '#cbd5e1',
        },
      },
      focus: {
        input: {
          borderColor: '#2563eb',
        },
      },
      error: {
        input: {
          borderColor: '#dc2626',
        },
      },
    },
  },
});

Precedence, most specific wins:

  1. State-specific category styles (e.g., state.hover.card.backgroundColor)
  2. Default-state category styles (state.default.card.backgroundColor)
  3. globalStyles passed to FastSpring.init() — applied as base defaults across every component

Anything you don't set falls back to the SDK default listed below.


Card (fs-card)

Renders the card-number, expiry, and CVV inputs inside a secure iframe.

Component options

Top-level options passed alongside style:

OptionTypeDefaultDescription
labelMode'fixed' | 'floating''floating'Label placement. 'floating' — labels start inside the input as a placeholder and animate to the top-left corner on focus or when the field has a value. 'fixed' — labels sit above each input.
hideCardHeaderbooleanfalseHide the panel header row (credit-card icon + "Card" title) when you have your own heading.

card — the panel

The outer container for the card form.

PropertyDefaultDescription
backgroundColor#ffffffPanel background
borderColor#DEE2E6Panel border color
borderWidth1pxPanel border width
borderRadius8pxPanel corner radius
border—Shorthand (e.g., '2px solid navy'); overrides borderColor + borderWidth
boxShadow0 2px 6px rgba(0,0,0,0.06)Panel shadow
padding0Inner padding
width100%Panel width — '100%' fills container, or a fixed value like '500px'
maxWidth680pxCaps panel width on wide screens. Set to 'none' to remove the cap.
gap0Gap between form rows
fontSize16pxBase font size
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifBase font family
color#4B5563Base text color
iconColorrgb(75, 85, 99)Header credit-card icon color. Hidden when hideCardHeader: true.

cardTitle — the "Card" header

PropertyDefaultDescription
color#4B5563Title text color
fontSize16pxTitle size
fontWeight550Title weight
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifTitle family

input — all input fields

Use input to style every card field at once. Use cardNumber, expiry, or cvv for per-field overrides — they accept the same properties.

Heads-up: depending on your session config, the SDK may also render a Zip Code field and a "Save Payment Details" checkbox alongside the card inputs. These don't have dedicated style categories yet — see Session-driven fields before designing a theme.

PropertyDefaultDescription
backgroundColor#ffffffInput background. Always applied as background-color (not the shorthand) to preserve card-brand badges.
borderColor#DEE2E6Border color
borderRadius4pxCorner radius
color#4B5563Text color
fontSize16pxFont size
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifFont family
fontWeight400Font weight
height48pxField height
padding0 16pxInner padding. In floating label mode the label follows the horizontal padding for px, rem and % values; font-relative units (em, ex, ch) are not supported for label alignment.
margin0Outer margin
outline—Focus-ring shorthand (e.g., '1px solid #bfdbfe')
outlineColorrgba(0, 138, 255, 0.2)Focus-ring color (flat alternative to outline)
placeholderColor#7D8A9BPlaceholder text color (flat alternative to '::placeholder'.color)
'::placeholder'—Nested placeholder styles — color, fontSize, fontFamily, fontWeight

Placeholder example:

input: {
  '::placeholder': {
    color: '#94a3b8',
    fontSize: '14px',
  },
}

cvvIcon — CVV graphic

A small card-silhouette graphic next to the CVV input.

PropertyDefaultDescription
height25pxIcon height; width scales proportionally
outlineColor#ABB5BEThe grey structural parts (card rectangle, circle border)
accentColor#008AFFThe colored digit strokes inside the circle
backgroundColortransparentBackground fill behind the icon

changeCard — "Use a different card" link

PropertyDefaultDescription
color#6b7280Link color
fontSize14pxLink size
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifLink family

inlineError — validation error messages

PropertyDefaultDescription
color#EB1431Error text color
fontSize12pxError font size
fontWeight400Error font weight
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifError font family (follows the component font)
backgroundColortransparentError message background

Card states

Out of the box, the Card visually changes for focus, error, and active. Other states (hover) accept overrides but apply no SDK-default differentiation — set them to add your own hover styling.

StateWhat changes by default
focusFocused input gets a blue border (#2563EB) and a soft blue glow
errorCard border, input border, and input text all turn red (#EB1431)
activeCard border becomes blue (#008aff); title font weight bumps to 600
hoverNo visual change unless you override

To style a state, set the same category/property under that state key:

style: {
  state: {
    focus: {
      input: {
        borderColor: '#2563eb',
      },
    },
    hover: {
      card: {
        backgroundColor: '#fafafa',
      },
    },
  },
}

Example — full Card customization

sdk.components.create('fs-card', {
  labelMode: 'floating',
  style: {
    state: {
      default: {
        card: {
          backgroundColor: '#ffffff',
          border: '1px solid #e5e7eb',
          borderRadius: '12px',
          padding: '24px',
          fontFamily: 'Inter, sans-serif',
        },
        cardTitle: {
          color: '#0f172a',
          fontSize: '18px',
          fontWeight: '600',
        },
        input: {
          backgroundColor: '#f9fafb',
          borderColor: '#e5e7eb',
          height: '48px',
          placeholderColor: '#9ca3af',
        },
        inlineError: {
          color: '#dc2626',
          fontSize: '13px',
        },
      },
      focus: {
        input: {
          borderColor: '#2563eb',
        },
      },
      error: {
        input: {
          borderColor: '#dc2626',
        },
      },
    },
  },
}).mount('#card-element');

Email (fs-email)

Collects the buyer's email address inside a secure iframe. Maps to customer.billToContact.email in the session. The component renders no section header — write your own heading above it on the page.

Component options

Top-level options passed alongside style:

OptionTypeDefaultDescription
labelMode'floating' | 'fixed''floating'Label placement. 'floating' — label starts inside the input as a placeholder and animates to the top on focus or when the field has a value. 'fixed' — label sits above the input.
fields{ email: 'auto' | 'readonly' | 'never' }{ email: 'auto' }Email field visibility. 'auto' — shown, editable, required (pre-filled if the session already has an email). 'readonly' — shown, pre-filled, locked. 'never' — hidden. 'readonly' and 'never' fall back to 'auto' when the session has no email, since an order can't be fulfilled without one.

email — component width

There is no panel around the field — background, border, and shadow come from your page. Text color and font are set per part (label, input, inlineError) or once for every component via globalStyles.

PropertyDefaultDescription
maxWidth680pxCaps component width on wide screens. Set to 'none' to remove the cap.

label — the field label

PropertyDefaultDescription
color#4B5563Label text color
fontSize14pxLabel size
fontWeight400Label weight
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifLabel family
backgroundColortransparentLabel background

input — the email field

PropertyDefaultDescription
backgroundColor#ffffffInput background
borderColor#DEE2E6Border color
borderRadius4pxCorner radius
color#4B5563Text color
fontSize16pxFont size
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifFont family
fontWeight400Font weight
height48pxField height
padding0 16pxInner padding
margin0Outer margin
outline—Focus-ring shorthand (e.g., '1px solid #bfdbfe')
outlineColorrgba(0, 138, 255, 0.2)Focus-ring color (flat alternative to outline)
errorBorderColor#EB1431Border color in the error state
placeholderColor#7D8A9BPlaceholder text color (flat alternative to '::placeholder'.color)
'::placeholder'—Nested placeholder styles — color, fontSize, fontFamily, fontWeight

Placeholder example:

input: {
  '::placeholder': {
    color: '#94a3b8',
    fontSize: '14px',
  },
}

inlineError — validation error messages

PropertyDefaultDescription
color#EB1431Error text color
fontSize12pxError font size
fontWeight400Error font weight
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifError font family (follows the component font)
backgroundColortransparentError message background

The component shows these messages:

SituationWhen it's shownMessage
Invalid email formatWhen the buyer leaves the field"Enter a valid email address."
Empty field (required)When the buyer clicks Pay"Enter your email address."

Email states

Out of the box, the Email form changes for focus and error.

StateWhat changes by defaultOverridable
focusFocused input gets a blue border (#2563EB) and a soft blue glowinput: borderColor, backgroundColor, outline
errorInput border, input text, and the floating label turn red (#EB1431)input: borderColor, backgroundColor, color · label: color (tints the floating label; defaults to following input.errorBorderColor) · inlineError: all properties
hoverNo visual change— (overrides under hover are not applied)

Combinations not listed are ignored. inlineError styling is also accepted under default; the error value wins when both are set.

To style a state, set the same category/property under that state key:

style: {
  state: {
    focus: {
      input: {
        borderColor: '#2563eb',
      },
    },
    error: {
      input: {
        borderColor: '#dc2626',
      },
    },
  },
}

Example — full Email customization

sdk.components.create('fs-email', {
  labelMode: 'floating',
  fields: { email: 'auto' },
  style: {
    state: {
      default: {
        email: {
          maxWidth: '520px',
        },
        label: {
          color: '#374151',
          fontSize: '14px',
          fontFamily: 'Inter, sans-serif',
        },
        input: {
          fontFamily: 'Inter, sans-serif',
          backgroundColor: '#f9fafb',
          borderColor: '#e5e7eb',
          height: '48px',
          placeholderColor: '#9ca3af',
        },
        inlineError: {
          color: '#dc2626',
          fontSize: '13px',
        },
      },
      focus: {
        input: {
          borderColor: '#2563eb',
        },
      },
      error: {
        input: {
          borderColor: '#dc2626',
        },
      },
    },
  },
}).mount('#email-element');

Apple Pay (fs-apple-pay)

Renders Apple's official Apple Pay button for the two-step flow. The button only appears in eligible browsers (Safari on macOS/iOS) on stores with Apple Pay enabled — elsewhere the component renders nothing and takes no space.

The button itself is drawn by Apple: its colors, label, and interaction states are governed by Apple's Human Interface Guidelines. The stylable surface is the variant option, the frame option, and two button properties. This component takes nothing from globalStyles.

Component options

Top-level options passed alongside style:

OptionTypeDefaultDescription
variant'black' | 'white''black'Apple button appearance. 'black' suits light checkouts; 'white' suits dark ones.
frame{ width, maxWidth }see belowThe component's own box: width and cap. A layout option, so it lives beside style, not inside it.

frame — the component's size

PropertyDefaultDescription
width100%Component width. Fills the container you mount it into.
maxWidth680pxCaps the component width on wide screens. Every component uses the same value. 'none' removes the cap.

button — the Apple Pay button

Maps onto Apple's public CSS custom-property surface for the real <apple-pay-button>. Width comes from frame; the button always fills it.

PropertyDefaultDescription
height48pxButton height. Apple permits a minimum of 30px.
borderRadius4pxCorner radius. Apple permits 0 to 50% of the height.

If a payment is declined, the Apple Pay window shows "This transaction has been declined. Please use a different payment method or contact your bank." and stays open so the buyer can try again.

Apple Pay states

Only the default state is wired. Hover/press feedback on the button is rendered natively by Apple and cannot be overridden; overrides under other state keys are ignored.

Example — full Apple Pay customization

sdk.components.create('fs-apple-pay', {
  variant: 'white',
  frame: { width: '100%', maxWidth: '480px' },
  style: {
    state: {
      default: {
        button: { height: '56px', borderRadius: '10px' },
      },
    },
  },
}).mount('#apple-pay-element');

Pay Button (fs-pay-button)

Submits payment when clicked. Styles apply as CSS on the underlying <button> element — any valid CSS property in camelCase works.

button — the button element

PropertyDefaultDescription
backgroundColor#2563EBButton background
color#ffffffLabel color
bordersolid 0pxShorthand border
borderColor#2563EBBorder color — same as the background, so it shows only once you set a borderWidth or border
borderRadius8pxCorner radius
padding28pxInner padding
margin0Outer margin
width400pxButton width
height54pxButton height
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifFont family
fontSize16pxFont size
fontWeight400Font weight
cursorpointerCursor style
opacity1Opacity

text — the button label

Styles applied to the <span> inside the button. By default, text properties inherit from the button.

PropertyDefaultDescription
colorinherits from button.colorText color
fontSizeinherits from button.fontSizeText size
fontWeightinherits from button.fontWeightText weight
fontFamilyinherits from button.fontFamilyText family

spinner — loading spinner

Circular SVG arc shown while a payment is in flight.

PropertyDefaultDescription
colorStart#E7E7E7Gradient start color (top of arc)
colorMid#ABB5BEGradient mid-point
colorEnd#7D8A9BGradient end color (bottom of arc)
size2remSpinner width and height

iofDisclaimer — Brazilian IOF fees notice

Rendered only when the session's complianceMessages array contains "SHOW_IOF_MESSAGE".

PropertyDefaultDescription
fontSize.75remDisclaimer font size
color#64748BDisclaimer text color

gdprNotice — GDPR data-privacy notice

Rendered for customers in GDPR-applicable countries (EU member states, UK, Norway, Switzerland, Japan). Includes auto-populated links to Terms of Service and Privacy Policy.

PropertyDefaultDescription
fontSize.75remNotice font size
color#64748BNotice text color
linkColor#2563ebTerms / Privacy Policy link color
linkHoverColor#2563EBLink color on hover

Pay Button states

StateWhen appliedWhat changes by default
defaultAlwaysBase styles above
hoverbutton:hoverBackground and border color shift to #1E4FC0. Other properties unchanged — override for full hover differentiation.
activebutton:active (mouse down / tap)No visual change unless overridden
disabledbutton:disabled (session not loaded / payment in progress)Opacity drops to 0.5, cursor becomes not-allowed
errorHost has [error] attributeNo visual change unless overridden
validHost has [valid] attributeNo visual change unless overridden
focusButton has keyboard focusOutline 2px solid #2563EB with 2px offset — the same blue a focused input border uses

Example — full Pay Button customization

sdk.components.create('fs-pay-button', {
  style: {
    state: {
      default: {
        button: {
          backgroundColor: '#16a34a',
          borderColor: '#15803d',
          borderRadius: '8px',
          width: '100%',
          fontWeight: '600',
        },
        text: {
          fontFamily: 'Inter, sans-serif',
        },
        spinner: {
          colorStart: '#dcfce7',
          colorMid:   '#86efac',
          colorEnd:   '#15803d',
          size: '1.5rem',
        },
      },
      hover: {
        button: {
          backgroundColor: '#15803d',
        },
      },
      active: {
        button: {
          backgroundColor: '#166534',
        },
      },
    },
  },
}).mount('#pay-button-element');

Disclosures (fs-disclosures)

Displays the FastSpring reseller disclosure — "Sold and fulfilled by FastSpring, an authorized reseller." — plus Privacy Policy and Terms of Sale links sourced automatically from session data.

The Privacy Policy and Terms of Sale links populate automatically when both URLs are present in the session data. No extra configuration needed.

container — the disclosure container

PropertyDefaultDescription
backgroundColortransparentContainer background
color#ABB5BEReseller disclosure text color
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifFont family
fontSize12pxFont size
padding12px 16pxInner padding
rowGap6pxGap between the reseller row and the links row

link — Privacy Policy / Terms of Sale links

PropertyDefaultDescription
color#2563ebLink color

Disclosures states

StateWhen appliedWhat changes by default
defaultAlwaysBase styles above
hoverCustomer hovers over a linkNo visual change unless overridden

Example — Disclosures customization

sdk.components.create('fs-disclosures', {
  style: {
    state: {
      default: {
        container: {
          color: '#64748b',
          fontFamily: 'Inter, sans-serif',
          fontSize: '12px',
        },
        link: {
          color: '#2563eb',
        },
      },
      hover: {
        link: {
          color: '#1d4ed8',
        },
      },
    },
  },
}).mount('#disclosures-container');

Coupon (fs-coupon)

Lets buyers apply, view, and remove a coupon code. In collapsed mode (the default) the input is hidden behind a "Have a coupon code?" toggle link; in expanded mode the input is always visible. Once a code is applied, the field is replaced by the applied chip.

Component options

OptionTypeDefaultDescription
presentation'collapsed' | 'expanded''collapsed'collapsed hides the input behind a toggle link; expanded shows it inline.
labelMode'floating' | 'fixed''floating'floating animates the label inside the field; fixed renders a static label above it (and shows a real placeholder).

input — the coupon code field

PropertyDefaultDescription
backgroundColor#fffInput background (background is accepted as a legacy alias)
color#4b5563Typed text color
borderColor#DEE2E6Default border
borderRadius4pxCorner radius
fontSize16pxInput text size
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifInput font
height48pxInput height
padding22px 16px 8px 16pxInner padding (top-heavy to seat the floating label)
placeholderColortransparentPlaceholder color. Transparent by default in floating mode (the label acts as the placeholder); set a visible color when using labelMode: 'fixed'.

state.focus.input.borderColor sets the focused border (default #2563EB).

state.error.input styles the field while the backend has rejected the code: borderColor and color (both default #EB1431), plus backgroundColor (default #fff) and fontFamily (default 'Helvetica Neue', Helvetica, Arial, sans-serif), the resting values above. These are the same four properties state.error.input takes on fs-card and fs-email.

button — the Apply button

PropertyDefaultDescription
background#008AFFButton background
color#fffLabel color
fontWeight400Label weight
borderRadius4pxCorner radius

state.hover.button.background (default #2563EB) and state.disabled.button.background (default #84C6FF) style the other states.

chip — the applied-coupon display

The {code} applied! text plus an × remove button, shown once a coupon is applied.

PropertyDefaultDescription
backgroundtransparentChip background
color#27B2A8Applied text color
borderRadius0Chip corner radius
padding4pxChip padding
gap8pxGap between text and the × button
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifChip font
fontSize12pxChip text size
fontWeight400Chip text weight
iconSize16px× icon size
iconColor#7D8A9B× icon color

state.hover.chip.iconColor (default #4b5563) styles the × on hover.

inlineError — validation error messages

Shown 4px below the input when the backend rejects a code. Same group name and properties as fs-card and fs-email, so one error style block ports across all three.

PropertyDefaultDescription
color#EB1431Error text color
fontSize12pxError font size
fontWeight400Error font weight
fontFamily'Helvetica Neue', Helvetica, Arial, sans-serifError font family (follows the component font)
backgroundColortransparentError message background

error is the deprecated name for this group. It still applies, logs one console warning per component, and loses to inlineError when both are set. Note that inlineError.color no longer drives the input's error border; use state.error.input.borderColor for that.

toggle — collapsed-mode link

The "Have a coupon code?" link, shown only in presentation: 'collapsed'.

PropertyDefaultDescription
color#008AFFLink color

state.hover.toggle.color (default #2563EB) styles it on hover.

Coupon states

StateWhen appliedWhat changes by default
defaultAlwaysBase styles above
focusInput focusedBorder turns #2563EB; floating label lifts and turns blue
hoverHover on Apply button, toggle link, or chip ×Button/toggle → #2563EB, chip icon → #4b5563
disabledDuring the apply/clear round-trip (Apply also looks disabled while the field is empty)Apply button → #84C6FF
errorBackend rejected the codeInput border and typed text turn #EB1431; the inlineError message ("The code you entered is not valid.") appears 4px below the field

Under error, input accepts borderColor, color, backgroundColor and fontFamily, and inlineError accepts all its properties. inlineError styling is also accepted under default; the error value wins when both are set.

Example — full Coupon customization

sdk.components.create('fs-coupon', {
  presentation: 'expanded',
  style: {
    state: {
      default: {
        input:  { background: '#0b1220', color: '#f1f5f9', borderColor: '#283449', borderRadius: '10px', placeholderColor: '#64748b' },
        button: { background: '#6366f1', color: '#ffffff', fontWeight: '600', borderRadius: '10px' },
        chip:   { color: '#a5b4fc', iconColor: '#64748b' },
        inlineError: { color: '#fca5a5', backgroundColor: '#1f1a2e' },
        toggle: { color: '#818cf8' },
      },
      focus: { input: { borderColor: '#6366f1' } },
      error: { input: { borderColor: '#f87171', color: '#fecaca' } },
      hover: { button: { background: '#4f46e5' }, toggle: { color: '#a5b4fc' } },
      disabled: { button: { background: '#3730a3' } },
    },
  },
}).mount('#coupon-element');

Global styles

Use globalStyles on FastSpring.init() to set defaults across every mounted component:

const sdk = FastSpring.init({
  checkoutUrl: 'https://<your-store>.onfastspring.com/<your-checkout>',
  globalStyles: {
    fontFamily: 'Inter, sans-serif',
    color: '#0f172a',
    fontSize: '14px',
  },
});

Component-level styles always win over global styles. Anything you don't set in either place falls back to the SDK defaults documented above.


A few patterns

Match the components to your brand color. Set state.default.button.backgroundColor on Pay Button and state.focus.input.borderColor on Card to your brand color — the two highest-impact overrides.

Dark mode. Override card.backgroundColor and input.backgroundColor to dark values, and bump color / input.color to a light tone. Don't forget input.borderColor and card.borderColor — they need to lift off the dark surface.

Visible hover on the Pay Button. The SDK doesn't apply a hover-state color shift by default. Add one:

hover: {
  button: {
    backgroundColor: '#1e40af',
  },
}

Custom focus ring. Set state.focus.input.borderColor and (optionally) state.default.input.outlineColor for the ring.

When changing the Card's base background, override the same property on hover/focus/active. The SDK ships with light-mode state defaults (#ffffff on the card panel for hover and active, #DEE2E6 on the border for hover). If you only set state.default.card.backgroundColor to a non-white value, the SDK's defaults will leak through on interaction and the card will appear to "flip" to white when the user hovers or focuses an input. Always pair a non-default base background with matching state overrides:

state: {
  default: {
    card: {
      backgroundColor: '#1e293b',
      borderColor: '#334155',
    },
  },
  hover: {
    card: {
      backgroundColor: '#1e293b',
      borderColor: '#334155',
    },
  },
  focus: {
    card: {
      backgroundColor: '#1e293b',
      borderColor: '#334155',
    },
  },
  active: {
    card: {
      backgroundColor: '#1e293b',
      borderColor: '#475569',
    },
  },
}

Session-driven fields

Before you commit to a theme, one thing to know: depending on your session configuration, the SDK may render additional fields beyond the style categories documented above. The two most common are a Zip Code input (when the session requires billing address) and a "Save Payment Details" checkbox (when the session permits saved payment methods).

These fields inherit base styling from card, input, and the global font/color settings, so they'll look broadly cohesive with whatever you've styled. They do not currently have dedicated style categories in the SDK style API — overriding input won't change their internal label color, background fill, or border treatment. The mismatch is most visible when your theme strays from the SDK's default light look (e.g., a dark or borderless preset).

If you need pixel-precise control over the Zip Code field or the Save Payment checkbox, contact FastSpring support — additional style hooks may be added in future SDK releases.

When testing or building presets, expect these fields to appear in the rendered output when:

  • The session was created with billing address requirements → Zip Code field appears below the CVV row
  • The session permits saving the payment method → "Save Payment Details" checkbox appears below the input fields

Presets

Three drop-in starting points. Pick the one closest to your site's look, paste it in, then tweak the brand-relevant values (typically the Pay Button background and the focus accent). Each preset styles all three components cohesively.

Preset 1 — Polished Light

Clean white card, modern sans-serif, blue Pay Button. The safe, professional baseline most B2B and SaaS sites land on.

const sdk = FastSpring.init({
  checkoutUrl: 'https://<your-store>.onfastspring.com/<your-checkout>',
  globalStyles: {
    fontFamily: 'Inter, ui-sans-serif, system-ui, sans-serif',
    color: '#0f172a',
    fontSize: '14px',
  },
  onSessionLoaded:  (data)  => console.log('Session loaded:', data),
  onOrderCompleted: (data)  => console.log('Order completed!', data),
  onPaymentFailed:  (error) => console.error('Payment failed:', error),
});

sdk.components.create('fs-card', {
  labelMode: 'floating',
  style: {
    state: {
      default: {
        card: {
          backgroundColor: '#ffffff',
          border: '1px solid #e5e7eb',
          borderRadius: '12px',
          padding: '24px',
          boxShadow: '0 1px 2px rgba(0,0,0,0.04)',
          color: '#0f172a',
          iconColor: '#475569',
        },
        cardTitle: {
          color: '#0f172a',
          fontSize: '16px',
          fontWeight: '600',
        },
        input: {
          backgroundColor: '#ffffff',
          borderColor: '#e2e8f0',
          borderRadius: '8px',
          color: '#0f172a',
          height: '48px',
          placeholderColor: '#94a3b8',
        },
        inlineError: {
          color: '#dc2626',
          fontSize: '13px',
        },
      },
      focus: {
        input: {
          borderColor: '#2563eb',
        },
      },
      error: {
        input: {
          borderColor: '#dc2626',
        },
      },
    },
  },
}).mount('#card-element');

sdk.components.create('fs-pay-button', {
  style: {
    state: {
      default: {
        button: {
          backgroundColor: '#2563eb',
          borderColor: '#2563eb',
          color: '#ffffff',
          borderRadius: '8px',
          width: '100%',
          height: '52px',
          fontSize: '15px',
          fontWeight: '600',
        },
      },
      hover: {
        button: {
          backgroundColor: '#1d4ed8',
        },
      },
      active: {
        button: {
          backgroundColor: '#1e40af',
        },
      },
      disabled: {
        button: {
          backgroundColor: '#94a3b8',
        },
      },
    },
  },
}).mount('#pay-button-element');

sdk.components.create('fs-disclosures', {
  style: {
    state: {
      default: {
        container: {
          color: '#64748b',
          fontFamily: 'Inter, sans-serif',
          fontSize: '12px',
          padding: '12px 0',
        },
        link: {
          color: '#2563eb',
        },
      },
      hover: {
        link: {
          color: '#1d4ed8',
        },
      },
    },
  },
}).mount('#disclosures-container');

Preset 2 — Dark

Dark card surface, light text, muted borders that still register against the background. Pairs well with dashboards, developer tools, and modern apps.

const sdk = FastSpring.init({
  checkoutUrl: 'https://<your-store>.onfastspring.com/<your-checkout>',
  globalStyles: {
    fontFamily: 'Inter, ui-sans-serif, system-ui, sans-serif',
    color: '#f1f5f9',
    fontSize: '14px',
  },
  onSessionLoaded:  (data)  => console.log('Session loaded:', data),
  onOrderCompleted: (data)  => console.log('Order completed!', data),
  onPaymentFailed:  (error) => console.error('Payment failed:', error),
});

sdk.components.create('fs-card', {
  labelMode: 'floating',
  style: {
    state: {
      default: {
        card: {
          backgroundColor: '#1e293b',
          border: '1px solid #334155',
          borderRadius: '12px',
          padding: '24px',
          boxShadow: '0 1px 2px rgba(0,0,0,0.3)',
          color: '#f1f5f9',
          iconColor: '#94a3b8',
        },
        cardTitle: {
          color: '#f1f5f9',
          fontSize: '16px',
          fontWeight: '600',
        },
        input: {
          backgroundColor: '#0f172a',
          borderColor: '#334155',
          borderRadius: '8px',
          color: '#f1f5f9',
          height: '48px',
          placeholderColor: '#64748b',
        },
        inlineError: {
          color: '#f87171',
          fontSize: '13px',
        },
      },
      hover: {
        card: {
          backgroundColor: '#1e293b',
          borderColor: '#334155',
        },
      },
      focus: {
        card: {
          backgroundColor: '#1e293b',
          borderColor: '#334155',
        },
        input: {
          borderColor: '#38bdf8',
        },
      },
      active: {
        card: {
          backgroundColor: '#1e293b',
          borderColor: '#475569',
        },
      },
      error: {
        card: {
          backgroundColor: '#1e293b',
          borderColor: '#f87171',
        },
        input: {
          borderColor: '#f87171',
          color: '#fecaca',
        },
      },
    },
  },
}).mount('#card-element');

sdk.components.create('fs-pay-button', {
  style: {
    state: {
      default: {
        button: {
          backgroundColor: '#0ea5e9',
          borderColor: '#0ea5e9',
          color: '#0f172a',
          borderRadius: '8px',
          width: '100%',
          height: '52px',
          fontSize: '15px',
          fontWeight: '600',
        },
      },
      hover: {
        button: {
          backgroundColor: '#0284c7',
        },
      },
      active: {
        button: {
          backgroundColor: '#0369a1',
        },
      },
      disabled: {
        button: {
          backgroundColor: '#475569',
          color: '#cbd5e1',
        },
      },
    },
  },
}).mount('#pay-button-element');

sdk.components.create('fs-disclosures', {
  style: {
    state: {
      default: {
        container: {
          color: '#94a3b8',
          fontFamily: 'Inter, sans-serif',
          fontSize: '12px',
          padding: '12px 0',
        },
        link: {
          color: '#38bdf8',
        },
      },
      hover: {
        link: {
          color: '#0ea5e9',
        },
      },
    },
  },
}).mount('#disclosures-container');

Preset 3 — Minimal

No card panel border, transparent surfaces, just the inputs and a flat button. The checkout reads as part of the host page rather than as a dropped-in widget. Good for landing pages and one-page checkouts that already have their own visual frame.

const sdk = FastSpring.init({
  checkoutUrl: 'https://<your-store>.onfastspring.com/<your-checkout>',
  globalStyles: {
    fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, sans-serif',
    color: '#111827',
    fontSize: '14px',
  },
  onSessionLoaded:  (data)  => console.log('Session loaded:', data),
  onOrderCompleted: (data)  => console.log('Order completed!', data),
  onPaymentFailed:  (error) => console.error('Payment failed:', error),
});

sdk.components.create('fs-card', {
  labelMode: 'floating',
  hideCardHeader: true,
  style: {
    state: {
      default: {
        card: {
          backgroundColor: 'transparent',
          border: 'none',
          boxShadow: 'none',
          padding: '0',
          maxWidth: 'none',
        },
        input: {
          backgroundColor: 'transparent',
          borderColor: '#d1d5db',
          borderRadius: '0',
          color: '#111827',
          height: '44px',
          padding: '0 4px',
          placeholderColor: '#9ca3af',
        },
        inlineError: {
          color: '#b91c1c',
          fontSize: '12px',
        },
      },
      hover: {
        card: {
          backgroundColor: 'transparent',
          borderColor: 'transparent',
        },
      },
      focus: {
        card: {
          backgroundColor: 'transparent',
          borderColor: 'transparent',
        },
        input: {
          borderColor: '#111827',
        },
      },
      active: {
        card: {
          backgroundColor: 'transparent',
          borderColor: 'transparent',
        },
      },
      error: {
        card: {
          backgroundColor: 'transparent',
          borderColor: 'transparent',
        },
        input: {
          borderColor: '#b91c1c',
        },
      },
    },
  },
}).mount('#card-element');

sdk.components.create('fs-pay-button', {
  style: {
    state: {
      default: {
        button: {
          backgroundColor: '#111827',
          borderColor: '#111827',
          color: '#ffffff',
          border: 'none',
          borderRadius: '0',
          width: '100%',
          height: '48px',
          fontSize: '14px',
          fontWeight: '500',
        },
      },
      hover: {
        button: {
          backgroundColor: '#1f2937',
        },
      },
      active: {
        button: {
          backgroundColor: '#374151',
        },
      },
      disabled: {
        button: {
          backgroundColor: '#9ca3af',
        },
      },
    },
  },
}).mount('#pay-button-element');

sdk.components.create('fs-disclosures', {
  style: {
    state: {
      default: {
        container: {
          color: '#6b7280',
          fontSize: '11px',
          padding: '8px 0',
        },
        link: {
          color: '#111827',
        },
      },
      hover: {
        link: {
          color: '#374151',
        },
      },
    },
  },
}).mount('#disclosures-container');

See also