Customize Embedded Checkout
Customise the Checkout Element's appearance using theme presets, CSS variables, custom rules, fonts, and locale settings.
Checkout Options
Pass these options when creating the checkout element:
| Option | Type | Description |
|---|---|---|
appearance | object | Theme, variables, and CSS rules for styling |
disabled | boolean | Disable all inputs in the checkout element |
hideSubmitButton | boolean | Hide the built-in submit button (use your own) |
submitButtonProps | object | Customise the built-in submit button (text, amount, style) |
cardOptions | object | Options specific to the card input |
applePayOptions | object | Options specific to the Apple Pay button, including the Apple Pay paymentRequest |
cardContainerStyle | object | Inline styles for the card input container |
applePayContainerStyle | object | Inline styles for the Apple Pay button container |
onTokenRefresh | function | Called when the session token needs refreshing - return a new token |
Callbacks
Register callbacks when creating the checkout element:
| Callback | Description |
|---|---|
onReady | Fired when the element is mounted and ready for interaction |
onChange | Fired when any input value changes |
onFocus | Fired when an input receives focus |
onBlur | Fired when an input loses focus |
onSuccess | Fired on successful payment - receives (response, paymentMethod) |
onError | Fired when a payment error occurs |
onTokenRefresh | Called when session token needs refresh - () => Promise<string> |
Saving a payment method
Set save_payment_method to true when you create the checkout session on your server. The card is entered inside Teya's secure iframe, so 3D Secure runs there and the card number never touches your systems — nothing changes in how you mount the element.
Two fields work together on the session. save_payment_method is what mints the token; type decides what the customer sees:
type | amount.value | What the element renders |
|---|---|---|
ACCOUNT_VERIFICATION | 0 | Saves the card without charging it. The submit button shows no price. |
SALE | The real amount | Saves the card alongside a real payment, and adds a consent checkbox that gates submission. |
If you send type: ACCOUNT_VERIFICATION with save_payment_method: false, Teya verifies the card but saves nothing.
const { session_token } = await (await fetch('/api/save-card-session')).json();
const teya = await initTeyaBlocks(session_token);
const checkout = teya.elements.create('checkout', {
submitButtonProps: { buttonText: 'Save card' },
onSuccess: async (response) => {
const authenticationId =
response?.checkout_payment_response?.online_transaction?.authentication_id;
await fetch('/account/cards/confirm', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ authenticationId }),
});
},
onError: (error) => console.error('Save failed', error),
});
checkout.mount('#checkout-container');
The token arrives on the payment.succeeded.v1 webhook as data.token_response.token_id, once the payment and the token have both been created successfully. Store it alongside data.payment_method.brand and last4 so you can render “Mastercard ••••4065” in your UI.
Saving an Apple Pay card
Apple only issues a reusable token when the customer agrees to a recurring payment on the Apple Pay sheet. Pass Apple's recurringPaymentRequest through applePayOptions.paymentRequest; the SDK forwards it to Apple and requests the Apple Pay version that returns the merchant token. Without it, an Apple Pay payment with save_payment_method: true saves nothing.
const checkout = teya.elements.create('checkout', {
applePayOptions: {
paymentRequest: {
recurringPaymentRequest: {
paymentDescription: 'Monthly plan',
regularBilling: {
label: 'Monthly plan',
amount: '9.99',
paymentTiming: 'recurring',
recurringPaymentIntervalUnit: 'month',
},
managementURL: 'https://example.com/account/subscriptions',
},
},
},
onSuccess: async (response) => { /* same as above */ },
});
The token arrives on the same webhook, with token_response.token_type: "WALLET_TOKEN". Store that value next to the token_id: a wallet token is charged with token_type: "WALLET_TOKEN" and initiator: MERCHANT only.
See Card on File for the consent rules and the wider flow, and Charge a Saved Payment Method for charging the token.
Theme Presets
Six built-in theme presets are available. Set the theme property in the appearance option:
const teya = await initTeyaBlocks('session-token', {
appearance: {
theme: 'default',
},
});
| Preset | Description |
|---|---|
default | Standard light theme |
dark | Dark background with light text |
minimal | Reduced visual chrome |
rounded | Larger border radius on inputs |
compact | Tighter spacing for dense layouts |
bold | Heavier font weights and borders |
Theme Variables
Override individual CSS variables using appearance.variables:
const teya = await initTeyaBlocks('session-token', {
appearance: {
theme: 'default',
variables: {
colorPrimary: '#0055ff',
colorBackground: '#ffffff',
colorText: '#333333',
borderRadius: '8px',
},
},
});
| Variable | Type | Description |
|---|---|---|
colorPrimary | string | Primary accent colour (focus rings, active states) |
colorBackground | string | Input background colour |
colorText | string | Input text colour |
colorDanger | string | Error and invalid state colour |
colorSuccess | string | Success state colour |
colorWarning | string | Warning state colour |
borderRadius | string | Input border radius |
borderWidth | string | Input border width |
borderColor | string | Input border colour |
fontFamily | string | Font family for all text |
fontSizeBase | string | Base font size |
fontWeightNormal | string | Normal font weight (default: 400) |
fontWeightMedium | string | Medium font weight (default: 500) |
fontWeightBold | string | Bold font weight (default: 700) |
spacingUnit | string | Base spacing unit used for padding and margins |
focusRingColor | string | Colour of the focus ring around inputs |
focusRingWidth | string | Width of the focus ring |
Custom CSS Rules
For more granular control, use appearance.rules to target specific selectors:
const teya = await initTeyaBlocks('session-token', {
appearance: {
rules: {
'.Input': {
border: '1px solid #ccc',
padding: '12px',
},
'.Input:focus': {
borderColor: '#0055ff',
boxShadow: '0 0 0 2px rgba(0, 85, 255, 0.2)',
},
'.Input--invalid': {
borderColor: '#dc3545',
},
'.Label': {
fontWeight: '600',
marginBottom: '4px',
},
},
},
});
Submit Button
Customise the built-in submit button or provide your own:
const checkout = teya.elements.create('checkout', {
hideSubmitButton: false,
submitButtonProps: {
buttonText: 'Pay now',
buttonAmount: '€10.00',
style: { backgroundColor: '#0055ff' },
},
});
Fonts
Set appearance.fontFamily to one of the built-in options loaded from Google Fonts:
| Value | Font |
|---|---|
system | System font stack (default) |
inter | Inter |
roboto | Roboto |
open-sans | Open Sans |
lato | Lato |
poppins | Poppins |
montserrat | Montserrat |
source-sans-pro | Source Sans Pro |
nunito | Nunito |
raleway | Raleway |
Locales
Set the locale option to change the language of labels, placeholders, and error messages:
const teya = await initTeyaBlocks('session-token', {
locale: 'de-DE',
});
Supported locales: en-GB (default), en-US, de-DE, es-ES, fr-FR, it-IT, pt-PT, da-DK, fi-FI, pl-PL, hr-HR, hu-HU, cs-CZ, is-IS, sk-SK.