The SDK accepts a theme object that controls the visual appearance of the card form inside the iframe. You only need to override the properties you want to change — everything else falls back to the default theme.
import { ZatlasCardCapture } from '@zatlas/card-capture' ;
const zatlas = new ZatlasCardCapture ({
publishableKey: 'pk_sandbox_your_key' ,
You only pass the values you want to change. The SDK deep-merges your overrides with the default theme.
The SDK ships three theme helpers:
Export Description defaultThemeLight theme with teal accents (matches Zatlas platform design) darkThemeDark background with lighter accents mergeTheme(partial)Deep-merges a partial theme object with defaultTheme
import { darkTheme } from '@zatlas/card-capture' ;
const zatlas = new ZatlasCardCapture ({
publishableKey: 'pk_sandbox_your_key' ,
To extend the dark theme:
import { darkTheme, mergeTheme } from '@zatlas/card-capture' ;
const customDark = mergeTheme ({
const zatlas = new ZatlasCardCapture ({
publishableKey: 'pk_sandbox_your_key' ,
You can change the theme after initialization with updateTheme(). This is useful for toggling between light and dark mode:
import { darkTheme } from '@zatlas/card-capture' ;
zatlas. updateTheme (darkTheme);
// Or pass a partial override
textPlaceholder: '#6B7280' ,
buttonBackground: '#34D399' ,
Property Default (light) Default (dark) Description colors.background#FFFFFF#1F2937Field background colors.backgroundHover#FAFBFC#374151Background on hover colors.backgroundDisabled#F5F5F7#111827Background when disabled colors.text#1A1B1C#F9FAFBInput text color colors.textPlaceholder#B6B7BF#6B7280Placeholder text colors.textError#D84B4B#F87171Error/validation message text colors.textDisabled#B6B7BF#4B5563Disabled text
Property Default (light) Default (dark) Description colors.border#B6B7BF#374151Default border colors.borderHover#CBCCD5#4B5563Border on hover colors.borderFocus#2D926E#34D399Border on focus colors.borderError#D84B4B#F87171Border on validation error colors.borderSuccess#2D926E#34D399Border on valid input
Property Default (light) Default (dark) Description colors.primary#2D926E#34D399Primary accent (focus ring, CTA default) colors.success#2D926E#34D399Success accent (valid field border)
Property Default (light) Default (dark) Description colors.icon#6D6E75#9CA3AFCard brand icon colors.iconError#D84B4B#F87171Icon on error colors.iconSuccess#2D926E#34D399Icon on success
Property Default Description colors.buttonBackground#2D926EButton background colors.buttonBackgroundHover#20674EButton background on hover colors.buttonText#FFFFFFButton text
Property Default Description colors.labelText#6D6E75Label above each field
Property Default Description colors.bannerErrorBackground#FEF2F2Banner background on payment decline colors.bannerErrorBorder#FECACABanner border colors.bannerErrorText#781D1DBanner message text
Property Default Description typography.fontFamily'Inter', system-ui, -apple-system, sans-serifFont stack typography.fontSize14pxBase font size typography.fontWeight400Font weight typography.lineHeight1.5Line height typography.letterSpacingnormalLetter spacing
Property Default Description borders.radius6pxCorner radius borders.width1pxBorder width borders.stylesolidBorder style (solid, dashed, dotted)
Property Default Description spacing.paddingX12pxHorizontal padding inside the field spacing.paddingY10pxVertical padding inside the field spacing.iconGap10pxGap between icon and input text
Property Default (light) Default (dark) Description shadows.focus0 0 0 3px #A2E0C50 0 0 3px rgba(52,211,153,0.25)Focus ring shadow shadows.error0 0 0 3px rgba(216,75,75,0.15)0 0 0 3px rgba(248,113,113,0.25)Error state shadow
Property Default Description transitions.duration150msAnimation duration transitions.timingease-in-outTiming function
The SDK injects a secure iframe into the element you pass to card.mount(). The iframe auto-resizes its height to fit the card form content. To ensure a smooth experience on all screen sizes, follow these guidelines.
Style your container element like you would a content block — give it a width, and let the iframe handle its own height:
< div id = "card-element" style = "width: 100%; max-width: 480px;" ></ div >
The iframe uses width: 100% to fill its container. You control the width; the SDK controls the height.
Do not constrain the container height
Never set a fixed height, max-height, or overflow: hidden on the container. The iframe needs to grow to fit all form fields and the CTA button. If the container clips the iframe, the guest will not see the submit button.
/* Bad — clips the card form */
/* Good — let the iframe grow */
The card form renders inside the iframe (card number, expiry, CVC, cardholder name, email, and the CTA button).
The iframe measures its content height and notifies the SDK via postMessage.
The SDK sets the iframe’s pixel height to match.
While the content loads, the iframe starts at a minimum height of 420px to prevent layout shift.
The card form works best between 300px and 600px wide. Below 300px, fields become cramped. Above 600px, the form looks sparse — consider centering it with max-width.
Container width Layout 300 — 480px Ideal for mobile and embedded flows 480 — 600px Comfortable on desktop
If you place the card element inside a flexbox or grid parent, make sure the container can grow vertically:
/* Flexbox parent — works fine */
/* Grid parent — works fine */
Avoid align-items: center on a flex parent with a fixed height — it can push the card form out of view on mobile. Use align-items: stretch (the default) or flex-start instead.
The card form is fully responsive. The expiry and CVC fields stay side by side on all screen sizes — they only need a few characters each. No media queries are needed in your CSS.
For mobile-first layouts, make the container full-width with padding: