Skip to main content

Migration Guide: v2 → v3

This guide covers every breaking change between @basis-theory/web-elements v2 and v3. Work through each section and use the upgrade checklist at the end to confirm your integration is complete.

The package name is unchanged: @basis-theory/web-elements. Only the major version changes.

1. Initialization

The most significant change in v3: initialization is now synchronous. The basistheory named export is replaced by a default BasisTheory constructor that returns an SDK instance immediately.

- import { basistheory } from '@basis-theory/web-elements';
+ import BasisTheory from '@basis-theory/web-elements';

- const bt = await basistheory('<PUBLIC_API_KEY>', { environment: 'test' });
+ const bt = BasisTheory('<PUBLIC_API_KEY>');

The environment option no longer exists. The SDK auto-detects the environment from the page origin (localhost → dev, btsandbox.com → UAT, everything else → production). To point at a specific API, use apiBaseUrl:

// Explicit API base URL (optional)
const bt = BasisTheory('<PUBLIC_API_KEY>', {
apiBaseUrl: 'https://api.btsandbox.com',
});

CDN global also changed from lowercase to uppercase:

- const bt = await basistheory('<PUBLIC_API_KEY>');
+ const bt = BasisTheory('<PUBLIC_API_KEY>');

2. Element types

Several element types were renamed, and two were removed.

v2 typev3 typeNotes
'cardNumber''cardNumber'Unchanged
'cardExpirationDate''expiry'Renamed
'cardVerificationCode''cvv'Renamed
'text''text'Unchanged
'card'Removed. Use cardNumber + expiry + cvv separately
'copyButton'Removed

The combined card element no longer exists. Replace it with three individual elements:

- const cardEl = bt.createElement('card', { targetId: 'card' });
- await cardEl.mount('#card');

+ 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'),
+ ]);

You will need to add two additional containers to your HTML:

- <div id="card"></div>
+ <div id="card-number"></div>
+ <div id="expiry"></div>
+ <div id="cvv"></div>

3. Events

Removed events

keydown, click, and copy events are not available in v3.

Added events

error is a new event in v3, fired when infrastructure or API errors occur on the element.

element.on('error', (event) => {
console.error(event.detail.code, event.detail.message);
});

Change event payload

The change event payload shape changed. Access event data via event.detail instead of directly on event:

- element.on('change', (event) => {
- if (event.complete) { ... }
- if (event.empty) { ... }
- if (event.errors) { ... }
- });

+ element.on('change', (event) => {
+ if (event.detail.isValid) { ... }
+ if (event.detail.isEmpty) { ... }
+ if (event.detail.error) { ... }
+ });

cardNumber change event — card metadata fields moved to event.detail:

- event.cardBrand
- event.cardLast4
- event.cardBin

+ event.detail.cardBrand
+ event.detail.last4
+ event.detail.bin

on() return value

on() now returns an unsubscribe function instead of a Subscription object:

- const subscription = element.on('change', handler);
- subscription.unsubscribe();

+ const unsubscribe = element.on('change', handler);
+ unsubscribe();

4. createElement options

The targetId option was removed. The target container is now passed to mount() instead:

- const el = bt.createElement('cardNumber', { targetId: 'my-card' });
- el.mount();

+ const el = bt.createElement('cardNumber');
+ await el.mount('#my-card');

Validation state tracking changed. Instead of reading state from element properties after a change event, read from event.detail:

- cardElement.on('change', () => {
- submitBtn.disabled = !cardElement.complete;
- });

+ cardNumberEl.on('change', (event) => {
+ submitBtn.disabled = !event.detail.isValid;
+ });

5. Tokenization

tokens.create is unchanged for card tokens. The data object field names are the same:

// Same in v2 and v3
await bt.tokens.create({
type: 'card',
data: {
number: cardNumberEl,
expiration_month: expiryEl,
expiration_year: expiryEl,
cvc: cvvEl,
},
});

The tokenize method (batch) signature is unchanged.

tokenIntents gains a get() method in v3 (was only create() in v2):

// New in v3
const intent = await bt.tokenIntents.get(intentId, { apiKey: sessionApiKey });

6. Theming

v3 introduces a design token system. Instead of passing CSS properties directly to elements for global styling, you now pass structured theme and optional darkTheme objects to BasisTheory():

- // v2: per-element style only, no global theme
- const el = bt.createElement('cardNumber', {
- style: { base: { color: '#111' } },
- });

+ // v3: design tokens at init — no per-element style option
+ const bt = BasisTheory('<PUBLIC_API_KEY>', {
+ themeMode: 'auto',
+ theme: {
+ colors: { primary: '#6366f1', text: { primary: '#111827' }, ... },
+ typography: { fontFamily: 'Inter', fontSize: { base: '16px' }, fontWeight: { normal: '400' } },
+ spacing: { sm: '8px', md: '12px', lg: '16px' },
+ borders: { radius: { base: '6px' }, width: { base: '1.5px' } },
+ },
+ });
+
+ const el = bt.createElement('cardNumber');

See Theming for the full token schema and dark mode setup.


7. React

Provider

The useBasisTheory(apiKey, options) initialization hook is replaced by BasisTheoryProvider:

- import { useBasisTheory, BasisTheoryProvider } from '@basis-theory/react-elements';
-
- function App() {
- const { bt, error } = useBasisTheory('<PUBLIC_API_KEY>', { environment: 'test' });
- if (!bt) return <div>Loading...</div>;
- return <BasisTheoryProvider bt={bt}><PaymentForm /></BasisTheoryProvider>;
- }

+ import { BasisTheoryProvider } from '@basis-theory/react-elements';
+
+ function App() {
+ return (
+ <BasisTheoryProvider apiKey='<PUBLIC_API_KEY>'>
+ <PaymentForm />
+ </BasisTheoryProvider>
+ );
+ }

useBasisTheory() inside the tree still works but now takes no arguments — it only reads from context:

- const { bt } = useBasisTheory('<PUBLIC_API_KEY>', options);
+ const { bt, error } = useBasisTheory(); // must be inside BasisTheoryProvider

Components

CardElement is removed. Replace it with the three separate element components:

- import { CardElement } from '@basis-theory/react-elements';
-
- <CardElement id="card" ref={cardRef} onChange={(e) => setComplete(e.complete)} />

+ import { CardNumberElement, ExpiryElement, CVVElement } from '@basis-theory/react-elements';
+
+ <CardNumberElement ref={cardNumberRef} onChange={(e) => setCardNumberValid(e.detail.isValid)} />
+ <ExpiryElement ref={expiryRef} onChange={(e) => setExpiryValid(e.detail.isValid)} />
+ <CVVElement ref={cvvRef} onChange={(e) => setCvvValid(e.detail.isValid)} />

Event prop payloads follow the same change as the web SDK — use event.detail.*:

- onChange={(event) => setComplete(event.complete)}
+ onChange={(event) => setValid(event.detail.isValid)}

Upgrade checklist

0 / 15 complete
Installation
Initialization
Element types
Element options
Events
React
Theming

Not yet available in V3

These v2 features are under consideration for future releases. This list is kept up to date as features are added to v3.

Services

  • bt.client — direct HTTP client for third-party endpoint requests

Element options

  • binLookup — BIN metadata lookup (brand, funding, issuer) returned in the change event binInfo object
  • Per-element style overrides — state variants (base, error, empty, complete) and pseudo-selectors (:hover, :focus, :disabled, ::placeholder, ::selection)
  • Custom Google Fonts — loading from the Google Fonts library

Methods

Events

  • keydown — keyboard event listener (altKey, ctrlKey, key, metaKey, shiftKey)

Init options


Coming to V3

These features are on the v3 roadmap and will be added in upcoming releases.

  • Proxy — proxy HTTP requests (GET/POST/PUT/PATCH/DELETE) through Basis Theory to third-party APIs
  • Whitelabel — enhanced whitelabel support for custom-domain element hosting
  • Copy Button — secure clipboard button for copying element values, including enableCopy, copyIconStyles, and the copy event
  • Cobadged — co-branded card network support (e.g., Cartes Bancaires) with selectedNetwork in change events
  • Dual Writing — write token data to multiple destinations simultaneously
  • Device Fingerprint — browser and device fingerprint collection

Not being ported

These v2 features were evaluated against usage patterns and will not be included in v3. If you rely on any of these features, contact support to discuss your use case.
  • Reveal (setValue) — programmatically populate an element with previously tokenized data
  • Custom Card Brand — custom card brand icons and detection logic