Migrate from Stripe Elements
MONEI Components mirror the Stripe Elements integration model: hosted iframes collect card data on your page, your PCI DSS scope stays at SAQ A, and your JavaScript never sees a card number. This page maps each Stripe concept to its MONEI equivalent.
Concept mapping
| Stripe | MONEI |
|---|---|
Stripe(publishableKey) | No global constructor — Components take paymentId or accountId directly. |
stripe.elements() | monei.CardGroup({...}) |
elements.create('card') | monei.CardInput({...}) |
elements.create('cardNumber') | monei.CardNumber({group}) |
elements.create('cardExpiry') | monei.CardExpiry({group}) |
elements.create('cardCvc') | monei.CardCvc({group}) |
element.mount('#id') | component.render('#id') |
stripe.createToken(cardElement) | cardGroup.submit() / cardInput.submit() |
stripe.confirmCardPayment(clientSecret) | monei.confirmPayment({paymentId, paymentToken}) |
element.on('change', handler) | onChange prop |
element.focus() / blur() / clear() | Same methods on a mounted part |
StripeElement--focus etc. | monei-component--focus etc. |
style option (per element) | style object |
fonts option | fonts: FontConfig[] |
Key structural difference: MONEI has no element factory. The group travels as a plain group prop on each part — every Component is created with monei.X({...}) and mounted with .render().
Split card fields
Stripe:
const elements = stripe.elements();
elements.create('cardNumber').mount('#number');
elements.create('cardExpiry').mount('#expiry');
elements.create('cardCvc').mount('#cvc');
const {token} = await stripe.createToken(elements.getElement('cardNumber'));
MONEI:
const cardGroup = monei.CardGroup({paymentId});
monei.CardNumber({group: cardGroup}).render('#number');
monei.CardExpiry({group: cardGroup}).render('#expiry');
monei.CardCvc({group: cardGroup}).render('#cvc');
const {token, error} = await cardGroup.submit();
Differences that work in your favor:
- Aggregate
onChangeon the group —CardGroup({onChange: ({complete}) => ...})tells you when all fields are valid. With Stripe you track each element'scompleteyourself. - Automatic focus advance — number → expiry → CVC as the customer types, with Backspace walking back. Stripe's split elements do not advance focus.
- Submit-time highlighting — a failed
submit()marks the offending part invalid; you only render the returnederrorstring.
Events
Stripe's change event payload maps almost one-to-one:
Stripe event | MONEI CardPartChangeEvent |
|---|---|
event.empty | event.empty |
event.complete | event.complete |
event.error.message | event.error (already a display-ready string) |
event.brand | event.brand (CardNumber only) |
ready → use onLoad. focus/blur → onFocus/onBlur (no payload).
Framework packages
| Stripe | MONEI |
|---|---|
@stripe/react-stripe-js <Elements> provider + useElements() | useCardGroup() — no provider needed |
<CardNumberElement /> etc. | <CardNumber group={group} /> etc. |
Vue, Angular and Svelte packages follow the same shape — see Vue, Angular and Svelte.
Server side
Replace PaymentIntents with MONEI payments: create a payment on your server, pass its id as paymentId to the group, then submit() + confirmPayment on the client — or confirm server-side with the token. Test with MONEI test cards.