Styling elements
Style Tokeflow Bridge SDK secure fields with the ElementStyle API and reflect live element state onto your own container with CSS.
Tokeflow's secure fields run inside isolated, cross-origin iframes; card data is encrypted in the browser and never touches your servers. Because the inputs live in another origin, you can't reach inside them with your page's CSS — so the Bridge SDK gives you a structured ElementStyle API to style the text inside the iframe, and a change event you use to style the container around the iframe.
Together, these two layers let secure fields blend seamlessly into your brand while keeping cardholder data fully isolated.
Styling is purely presentational. It never changes how data is collected, encrypted, or tokenized — see Tokenization for the data flow.
The two styling layers
There are two distinct surfaces, and they're styled in two different ways.
| Layer | What it styles | How you style it |
|---|---|---|
| Inside the iframe | The input text, placeholder, and caret rendered by the secure field | ElementStyle object passed as style |
| Around the iframe | Borders, padding, background, focus ring, validation states | Your own CSS, driven by the change event |
The ElementStyle API
Pass a style object when you create an element. It maps style rules to the input rendered inside the iframe.
const style = {
base: {
color: '#333333',
fontSize: '16px',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
fontWeight: '400',
lineHeight: '24px',
'::placeholder': { color: '#aaaaaa', fontStyle: 'italic' },
':focus': { color: '#000000' },
},
complete: { color: '#28a745' }, // input is complete and valid
invalid: { color: '#dc3545' }, // input is invalid
empty: { color: '#6c757d' }, // input is empty
};
const cardElement = tokeflow.createCardElement({ style });Base styles
The base object holds the default appearance, applied in every state unless overridden by a state-specific block. These are the core typographic properties supported.
| Property | Type | Description |
|---|---|---|
color | string | Text color of the input value (any CSS color). |
fontSize | string | Font size of the input text, e.g. "16px". |
fontFamily | string | Font stack for the input text. See Loading custom fonts. |
fontWeight | string | Font weight, e.g. "400" or "600". |
lineHeight | string | Line height of the input text, e.g. "24px". |
Match fontSize, fontFamily, and lineHeight to your surrounding form inputs so the secure field is visually indistinguishable from your native fields.
Pseudo-selectors
Inside base, two pseudo-selectors let you target sub-states of the input.
| Selector | Targets |
|---|---|
::placeholder | The placeholder text shown while the field is empty. |
:focus | The input while it has focus. |
Each accepts the same typographic properties as base:
const style = {
base: {
color: '#1a1a1a',
fontSize: '16px',
'::placeholder': {
color: '#9aa0a6',
fontStyle: 'italic',
},
':focus': {
color: '#000000',
},
},
};State styles
Beyond base, you can supply top-level state blocks that override the base color (and other properties) as the cardholder's input changes. The SDK applies them automatically based on the element's live state.
| State | Applied when | Typical use |
|---|---|---|
empty | The field has no value yet | Mute the caret/text color before input |
complete | The value is complete and valid | Confirm success with a green tone |
invalid | The current value fails validation | Warn with a red tone |
const style = {
base: {
color: '#333333',
fontSize: '16px',
lineHeight: '24px',
},
empty: { color: '#6c757d' },
complete: { color: '#28a745' },
invalid: { color: '#dc3545' },
};State styles only affect properties you can set on the input text (such as color). To restyle the frame — borders, background, shadows — drive your container with the change event, covered in Container styling.
Loading custom fonts
If your fontFamily references a web font that isn't a system font, declare it via the fonts array so the iframe can load it. Use the same option on elementOptions (applied to every element) or per element.
const tokeflow = new TokeflowBridge({
publicKey: 'pk_live_mer_xxxxxxxx',
elementOptions: {
fonts: ['https://fonts.example.com/inter.css'],
style: {
base: {
fontFamily: '"Inter", sans-serif',
fontSize: '16px',
},
},
},
});Public keys (pk_live_…) are safe to ship in browser code. Never put a secret key (sk_live_…) in client-side code — see Authentication.
Container styling
The iframe sits inside a container element you control. Style that container with ordinary CSS to handle everything the iframe can't: borders, padding, background, focus rings, and validation states.
Two techniques work together:
:focus-within— a native CSS pseudo-class that matches your container whenever the focus is inside it (including inside the iframe). Use it for the focus ring with no JavaScript required.- State classes from the
changeevent — toggle your own classes (e.g.invalid,complete) on the container in response to the element's live state.
CSS
.card-element-container {
border: 1px solid #dddddd;
border-radius: 8px;
padding: 12px;
background: #fafafa;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
/* Focus ring — pure CSS, fires when focus is inside the iframe */
.card-element-container:focus-within {
border-color: #0066ff;
box-shadow: 0 0 0 3px rgba(0, 102, 255, 0.15);
}
/* Validation states — toggled from the change event */
.card-element-container.invalid {
border-color: #dc3545;
}
.card-element-container.complete {
border-color: #28a745;
}JavaScript
Mount the element into the container, then reflect its state onto the container from the change event.
const cardElement = tokeflow.createCardElement({ style });
cardElement.mount('.card-element-container');
const container = document.querySelector('.card-element-container');
cardElement.on('change', (event) => {
// event.error is singular; event.empty / event.complete are booleans
container.classList.toggle('invalid', !!event.error && !event.empty);
container.classList.toggle('complete', event.complete);
});The change event payload exposes only non-sensitive state and metadata — never the raw card data:
interface ElementChangeEvent {
elementType: ElementType;
empty: boolean;
complete: boolean;
error?: ElementError; // singular — there is no `errors` array
value?: { // non-sensitive metadata only
type?: string;
brand?: string; // e.g. 'visa', 'mastercard'
bin?: string;
last4?: string;
};
}You can also read the same state synchronously at any time with element.getState(), which returns { empty, focused, valid, invalid, complete, error? }. The change event is best for live UI; getState() is best for one-off checks (for example, before tokenizing).
Putting it together
A minimal, fully styled card field:
<div class="card-element-container"></div>const tokeflow = new TokeflowBridge({ publicKey: 'pk_live_mer_xxxxxxxx' });
await tokeflow.init();
const cardElement = tokeflow.createCardElement({
style: {
base: {
color: '#1a1a1a',
fontSize: '16px',
fontFamily: '"Inter", sans-serif',
lineHeight: '24px',
'::placeholder': { color: '#9aa0a6' },
},
complete: { color: '#28a745' },
invalid: { color: '#dc3545' },
},
placeholder: {
cardNumber: '1234 5678 9012 3456',
cardExpirationDate: 'MM/YY',
cardSecurityCode: 'CVC',
},
});
cardElement.mount('.card-element-container');
const container = document.querySelector('.card-element-container');
cardElement.on('change', (event) => {
container.classList.toggle('invalid', !!event.error && !event.empty);
container.classList.toggle('complete', event.complete);
});Advanced theme object
ElementStyle covers the common cases. For finer-grained control, you can pass a lower-level theme object instead, with a styles map keyed by internal selectors. This is an escape hatch for advanced layouts and is not needed by most integrations.
const cardElement = tokeflow.createCardElement({
theme: {
styles: {
'.field input': { fontSize: 16, color: '#333333' },
},
},
});The theme selectors target internal element structure and are less stable across SDK versions than ElementStyle. Prefer ElementStyle for portability, and reach for theme only when you need a rule ElementStyle doesn't expose.
Next steps
- Bridge SDK overview — install the SDK and create elements.
- Tokenization — turn collected card data into a token reference.
- Authentication — public vs. secret keys and where each belongs.