Step-by-step guide to creating and customizing your own card payment form with Primer Checkout.
This tutorial walks you through building a custom card form with Primer Checkout. You’ll learn how to customize the layout, style the inputs, handle events, and avoid common pitfalls.
The <primer-card-form> component provides a customizable card payment interface with PCI-compliant hosted inputs. Here’s how the components relate to each other:
Cprimer-checkout
└── Mprimer-main
└── ◇primer-payment-methodtype="PAYMENT_CARD"
└── Fprimer-card-formrenders automatically
├── #primer-input-card-number
├── #primer-input-card-expiry
├── #primer-input-cvv
├── #primer-input-cardholder-name
└── →primer-card-form-submit
CRoot
MLayout
PContainer
FCard form
#Input fields
→Actions / errors
◇Payment method
Security by designThe card input components (primer-input-card-number, primer-input-card-expiry, primer-input-cvv) render secure iframes that isolate sensitive card data. This means:
Card data never touches your page’s DOM
Your integration remains PCI-compliant
Styling is applied through CSS variables that are passed to the iframe
Component hierarchy mattersAll card input components must be nested inside <primer-card-form>. Placing them outside breaks the context connection and the form won’t work.
If you collect the cardholder name elsewhere (e.g., from a shipping form), you can set it programmatically:
Copy
Ask AI
const cardForm = document.querySelector('primer-card-form');// Set cardholder name from your formconst name = document.getElementById('shipping-name').value;cardForm.setCardholderName(name);
When using setCardholderName(), you don’t need to include the <primer-input-cardholder-name> component in your form.
Don’t include both <primer-card-form> and <primer-payment-method type="PAYMENT_CARD"> in your layout. The payment method component already renders a card form internally.
Copy
Ask AI
<!-- WRONG: Duplicate card forms --><div slot="payments"> <primer-card-form>...</primer-card-form> <primer-payment-method type="PAYMENT_CARD"></primer-payment-method></div><!-- CORRECT: Use one or the other --><div slot="payments"> <primer-card-form>...</primer-card-form> <primer-payment-method type="PAYPAL"></primer-payment-method></div>
Inputs outside the form context
Card input components must be descendants of <primer-card-form>. They won’t work if placed outside.
When rendering card forms dynamically, ensure the parent <primer-card-form> exists before adding input children:
Copy
Ask AI
// WRONG: Adding inputs before the formcontainer.innerHTML = ` <primer-input-card-number></primer-input-card-number> <primer-card-form></primer-card-form>`;// CORRECT: Form first, then inputscontainer.innerHTML = ` <primer-card-form> <div slot="card-form-content"> <primer-input-card-number></primer-input-card-number> </div> </primer-card-form>`;
Missing slot attribute
When customizing the card form layout, always use the card-form-content slot:
Copy
Ask AI
<!-- WRONG: Content not in a slot --><primer-card-form> <div> <primer-input-card-number></primer-input-card-number> </div></primer-card-form><!-- CORRECT: Content in the card-form-content slot --><primer-card-form> <div slot="card-form-content"> <primer-input-card-number></primer-input-card-number> </div></primer-card-form>