@basis-theory/web-elements
v3.0.0
Published
Secure, PCI-compliant elements for creating payment input forms
Downloads
193,998
Readme
@basis-theory/web-elements
Secure, PCI-compliant iframe elements for collecting sensitive data in web applications. Card data never touches your servers.
Installation
npm
npm install @basis-theory/web-elements@betayarn
yarn add @basis-theory/web-elements@betaCDN
<script src="https://js.basistheory.com/3.0.0-beta.2/web-elements/basis-theory.js"></script>Quick Start
import BasisTheory from '@basis-theory/web-elements';
// Initialize (synchronous -- returns immediately)
const bt = BasisTheory('pk_test_...');
// Create elements
const cardNumberEl = bt.createElement('cardNumber', {
placeholder: '4242 4242 4242 4242',
});
const expiryEl = bt.createElement('expiry', {
placeholder: 'MM/YY',
});
const cvvEl = bt.createElement('cvv', {
placeholder: '123',
});
// Mount to DOM (async -- creates secure iframes)
await Promise.all([
cardNumberEl.mount('#card-number'),
expiryEl.mount('#expiry'),
cvvEl.mount('#cvv'),
]);
// Listen for validation changes
cardNumberEl.on('change', (event) => {
console.log('Valid:', event.detail.isValid);
console.log('Brand:', event.detail.cardBrand);
});
// Tokenize on form submission
const token = await bt.tokens.create({
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
});
console.log('Token ID:', token.id);CDN Usage
<script src="https://js.basistheory.com/3.0.0-beta.2/web-elements/basis-theory.js"></script>
<script>
document.addEventListener('DOMContentLoaded', async () => {
const bt = BasisTheory('pk_test_...');
const cardNumberEl = bt.createElement('cardNumber');
const expiryEl = bt.createElement('expiry');
const cvvEl = bt.createElement('cvv');
await Promise.all([
cardNumberEl.mount('#card-number'),
expiryEl.mount('#expiry'),
cvvEl.mount('#cvv'),
]);
});
</script>Element Types
| Type | createElement key | Description |
|------|---------------------|-------------|
| Card Number | 'cardNumber' | PAN input with Luhn validation and brand detection |
| Expiry | 'expiry' | MM/YY expiration date input |
| CVV | 'cvv' | Card verification code input |
| Text | 'text' | General-purpose secure text input (SSN, routing numbers, etc.) |
Shared Options
All element types accept these options in createElement() and element.update():
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| placeholder | string | -- | Placeholder text shown when the input is empty |
| ariaLabel | string | Element-specific | ARIA label for screen readers |
| disabled | boolean | false | Disables the input |
| readOnly | boolean | false | Makes the input read-only |
Text Element Options
| Option | Type | Description |
|--------|------|-------------|
| validation | RegExp | Pattern the value must match to be valid |
| required | boolean | Whether the field is required |
| maxLength | number | Maximum character length |
| password | boolean | Renders as a password field |
| inputMode | string | Mobile keyboard hint ('numeric', 'tel', etc.) |
| mask | (RegExp \| string)[] | Character-by-character input mask |
| transform | [RegExp, string] | Transform applied before tokenization |
CVV Element Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| showToggle | boolean | false | Renders a show/hide toggle button inside the field |
Element Methods
Every element exposes the same interface:
| Method | Signature | Description |
|--------|-----------|-------------|
| mount | (selector: string \| HTMLElement) => Promise<void> | Attaches the iframe to the DOM |
| unmount | () => void | Removes the iframe from the DOM |
| update | (options) => Promise<void> | Updates options on a mounted element |
| focus | () => void | Focuses the input |
| blur | () => void | Blurs the input |
| clear | () => void | Clears the current value |
| on | (event, listener) => () => void | Subscribes to an event; returns an unsubscribe function |
Properties: id (string), type (ElementType), mounted (boolean).
Events
| Event | Fires when |
|-------|-----------|
| ready | Element iframe is loaded and interactive |
| change | Input value changes |
| focus | Element receives focus |
| blur | Element loses focus |
| error | An infrastructure or API error occurs |
change Event Payload
All elements include these fields in event.detail:
| Field | Type | Description |
|-------|------|-------------|
| isValid | boolean | Input passes all validation rules |
| isEmpty | boolean | Input is empty |
| error | ValidationError \| null | Validation error, or null if valid |
| elementType | string | Element type that fired the event |
| elementId | string | Unique element ID |
| timestamp | number | Unix timestamp (ms) |
The cardNumber element adds: cardBrand, last4, bin, cvvLengths, potentialBrands, and matchStrength.
cardNumberEl.on('change', (event) => {
const { isValid, cardBrand, last4 } = event.detail;
console.log(`${cardBrand} ...${last4}`, isValid);
});error Event Codes
| Code | Description |
|------|-------------|
| MOUNT_ERROR | Failed to mount the element iframe |
| POSTMESSAGE_TIMEOUT | PostMessage timeout |
| IFRAME_LOAD_ERROR | Element iframe failed to load |
| INITIALIZATION_ERROR | SDK or coordinator failed to initialize |
| API_ERROR | Basis Theory API returned an error |
| NETWORK_ERROR | Network request failed |
| VALIDATION_ERROR | Input failed client-side validation |
| INVALID_CONFIGURATION | Invalid SDK or element options |
| UNKNOWN_ERROR | Unexpected error |
SDK Options
const bt = BasisTheory('pk_test_...', {
debug: false, // Enable verbose debug logging
themeMode: 'auto', // 'light' | 'dark' | 'auto'
theme: { /* ThemeTokens */ },
darkTheme: { /* ThemeTokens */ },
timeoutMs: 30000, // PostMessage timeout (ms)
});Services
tokens
// Create a token
const token = await bt.tokens.create({
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
});
// Retrieve a token
const retrieved = await bt.tokens.retrieve(token.id, {
apiKey: sessionApiKey, // from an authorized session
});
// Update a token
await bt.tokens.update(token.id, {
metadata: { source: 'updated' },
});
// Encrypt with client-side JWE
const encrypted = await bt.tokens.encrypt(
{ type: 'card', data: { number: cardNumberEl, cvc: cvvEl } },
publicKeyPEM,
'key-id-123'
);tokenize
const result = await bt.tokenize({
number: cardNumberEl,
cvv: cvvEl,
expiry: expiryEl,
});tokenIntents
const intent = await bt.tokenIntents.create({
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
});
const retrieved = await bt.tokenIntents.get(intent.id);sessions
const session = await bt.sessions.create();
// Send session.nonce to your backend to authorize
// Backend returns an apiKey for elevated access
const token = await bt.tokens.retrieve(tokenId, {
apiKey: sessionApiKey,
});Theming
Pass design tokens at initialization and switch modes at runtime:
const bt = BasisTheory('pk_test_...', {
themeMode: 'auto',
theme: {
colors: {
primary: '#007bff',
error: '#dc3545',
success: '#28a745',
text: { primary: '#1a1a1a', placeholder: '#6c757d' },
background: { default: '#ffffff' },
border: { default: '#dee2e6', focus: '#007bff' },
},
typography: {
fontFamily: 'Inter, sans-serif',
fontSize: { base: '16px' },
fontWeight: { normal: '400' },
},
spacing: { sm: '8px', md: '12px', lg: '16px' },
borders: {
radius: { base: '6px' },
width: { base: '1px' },
},
},
});
// Switch theme mode at runtime
await bt.updateThemeMode('dark');TypeScript
The package ships full type definitions. Key exports:
import type {
BasisTheorySDK,
Element,
ElementType,
ElementOptions,
SDKOptions,
ChangeEventDetail,
CardNumberChangeEventDetail,
ReadyEventDetail,
ErrorEventDetail,
ErrorCode,
ValidationError,
TokenizeResult,
Session,
} from '@basis-theory/web-elements';Documentation
Full documentation: https://developers.basistheory.com/docs/sdks/web/web-elements/
License
Apache-2.0
