Skip to main content

Hosted Fields

Use the getHostedFields() method to render individual, PCI-compliant card input fields as secure iframes within your own custom form layout. Each field (card number, expiry, CVV…) is isolated inside a separate iframe while your page retains full control over the surrounding UI.

When to use this recipe
  • You want to build a fully custom card form UI (layout, labels, styles all yours).
  • You are collecting vault credit card data only.
  • You need PCI-DSS compliant field isolation without managing sensitive data yourself.
Vault credit card only

getHostedFields() is only available for vault credit card payment methods. For other methods, use getPaymentElement() instead. For a pre-built form that also handles theming, see Hosted Form.

Prerequisites

This recipe assumes you have a checkout instance already initialized. See the Getting Started guide if you haven't done this yet.


1. Add form containers to your HTML​

Create placeholder div elements for each card field. The SDK will inject secure iframes into these targets:

<form id="payment-form">
<div class="field">
<label>Card Number</label>
<div class="row">
<div id="card-number"></div>
<div id="brand-selector"></div>
</div>
</div>

<div class="field">
<label>Cardholder Name</label>
<div id="cardholder-name"></div>
</div>

<div class="row">
<div class="field">
<label>Expiry Date</label>
<div id="expiry-date"></div>
</div>
<div class="field">
<label>CVV</label>
<div id="cvv"></div>
</div>
</div>

<button type="submit" id="submit-btn">Pay Now</button>
<div id="error"></div>
</form>

2. Render the hosted fields​

Subscribe to payment methods, retrieve the credit card method, call getHostedFields() with your target element IDs, then call render():

checkout.paymentMethods.subscribe((methods) => {
const creditCard = methods.find(m => m.method === "creditcard");

if (creditCard) {
const hostedFields = creditCard.getHostedFields({
fields: {
brandSelector: { target: "brand-selector" },
cardNumber: { target: "card-number", placeholder: "1234 5678 9012 3456" },
holderName: { target: "cardholder-name", placeholder: "John Doe" },
expDate: { target: "expiry-date", placeholder: "MM/YY" },
cvv: { target: "cvv", placeholder: "123" }
}
});

hostedFields.render();
}
});

πŸ’‘ render() mounts one secure iframe per target element. The brandSelector field is optional β€” it displays a brand icon based on the card number entered.

3. Customize field appearance​

Pass a theme object to getHostedFields() to style the fields from the outside. Only global and input scopes are supported:

const hostedFields = creditCard.getHostedFields({
fields: { /* ...same as above... */ },
theme: {
global: {
fontFamily: 'Inter, sans-serif',
fontSize: '16px'
},
input: {
color: "#111827",
backgroundColor: "#ffffff",
':focus': { color: "#111827" },
':invalid': { color: "#dc2626" }
}
}
});
Theme scope reference

See Theme references for all available keys. For richer theming (labels, helper text, tooltips), use Hosted Form instead.

Custom fonts​

Contact required

For compliance reasons, please contact the Purse team before using custom fonts β€” you must provide the font file in advance.

Pre-approved Google Fonts (Inter, Lato, Montserrat, Noto, Nunito, Open Sans, Raleway, Roboto, Work Sans) are ready to use without approval β€” just set fontFamily:

theme: {
global: {
fontSrc: 'custom-font-file', // only needed for non-pre-approved fonts
fontFamily: 'Inter, sans-serif',
fontSize: '16px'
}
}

4. Handle form submission​

Call checkout.submitPayment() on form submit:

document.getElementById("payment-form").addEventListener("submit", async (e) => {
e.preventDefault();

const submitBtn = document.getElementById("submit-btn");
const errorDiv = document.getElementById("error");

submitBtn.disabled = true;
submitBtn.textContent = "Processing...";
errorDiv.style.display = "none";

try {
await checkout.submitPayment();
// Redirect or show success message
} catch (error) {
errorDiv.textContent = error.message || "Payment failed";
errorDiv.style.display = "block";
} finally {
submitBtn.disabled = false;
submitBtn.textContent = "Pay Now";
}
});

Error handling​

Common errors
  • Expired session β†’ Create a new client session
  • Invalid field configuration β†’ Check that all target element IDs exist in the DOM
  • Payment method not supported β†’ The method does not support Hosted Fields (only vault credit card is supported)
  • Technical error β†’ The payment method could not be initialized

Complete example​

Loading demo…

See also​

  • Brand Management β€” Detect and manage co-branded cards with getHostedFields()
  • Hosted Form β€” Use a pre-built form UI via getPaymentElement({ hostedForm })
  • Customization β€” Theming the default payment element with getPaymentElement()