Events
As users interact with Hosted Payment Component fields, custom DOM events are dispatched on each container element. These allow you to react to changes in validation state, focus, and detected card brand without polling or relying solely on CSS class changes.
Available Events
Four custom events are available:
| Event Name | Triggered When | Detail Object |
|---|---|---|
hpc.focus | The field gains or loses keyboard focus | { focus: boolean } |
hpc.validation | The validation state of the field changes | { validation: { valid, invalid, empty } } |
hpc.cardBrand | A card brand is detected from the entered number | { cardBrand: string } |
hpc.initializationComplete | The component has finished initializing and is ready for input | {} (empty) |
Listening for Events
Attach event listeners to your container elements using standard DOM APIs. The events are dispatched on the container element (the div with the configured id), not on elements inside the iframe.
// Get reference to the container element
const cardNumberContainer = document.getElementById('exampleCardNumber');
// Listen for validation changes
cardNumberContainer.addEventListener('hpc.validation', function (e) {
const state = e.detail.validation;
console.log("Valid:", state.valid);
console.log("Invalid:", state.invalid);
console.log("Empty:", state.empty);
});
// Listen for focus changes
cardNumberContainer.addEventListener('hpc.focus', function (e) {
console.log("Field focused:", e.detail.focus);
});
// Listen for card brand detection
cardNumberContainer.addEventListener('hpc.cardBrand', function (e) {
console.log("Detected card brand:", e.detail.cardBrand || "Unknown");
});
Event Details
hpc.validation
Dispatched whenever the validation state of a field changes. This includes when the user starts typing, finishes entering data, or corrects invalid input.
The detail object contains:
| Property | Type | Description |
|---|---|---|
validation.valid | Boolean | true if the field content passes all validation rules |
validation.invalid | Boolean | true if the field content fails validation (e.g., incomplete card number, invalid expiry date) |
validation.empty | Boolean | true if the field is empty or has not been interacted with |
At any given time, exactly one of these three properties will be true. For example, a partially entered but valid-so-far card number may have valid: true, while an incomplete entry that fails Luhn check will have invalid: true.
Example usage — enabling the Pay button only when all fields are valid:
// Enable Pay button only when all fields are valid
const fields = ['exampleCardNumber', 'exampleExpiryDate', 'exampleCVV'];
function testValidity() {
document.getElementById('examplePay')
.disabled = !fields.every((id) => document.getElementById(id).classList.contains('is-valid'));
}
fields.forEach((id) => document.getElementById(id).addEventListener('hpc.validation', (e) => testValidity()));
testValidity();
hpc.focus
Dispatched when the field gains or loses keyboard focus. Useful for implementing custom focus indicators beyond what feedback classes provide.
The detail object contains:
| Property | Type | Description |
|---|---|---|
focus | Boolean | true if the field has gained focus, false if it has lost focus |
Example usage — logging focus transitions for analytics:
document.getElementById('exampleCardNumber').addEventListener('hpc.focus', function (e) {
if (e.detail.focus) {
console.log("User started entering card number");
} else {
console.log("User left card number field");
}
});
hpc.cardBrand
Dispatched when a card brand is detected from the entered card number. This event may fire multiple times as the user types if the brand detection changes (e.g., typing a number that initially matches Visa but later matches Mastercard).
The detail object contains:
| Property | Type | Description |
|---|---|---|
cardBrand | String | The detected card brand name, or an empty string if no brand could be identified |
Currently the following brands are detected and returned:
| brand name | Description |
|---|---|
| visad | Visa Debit |
| visae | Visa Electron |
| visa | Visa Credit/Debit |
| visac | Visa Credit |
| mastd | Mastercard Debit |
| mastc | Mastercard Credit |
| maestrou | Maestro UK |
| maestroi | Maestro International |
| jcb | JCB |
| amex | Amex |
| diners | Diners |
| discover | Discover |
| visatest | Sandbox test cards (sandbox only) |
Example usage — displaying a card brand icon next to the field:
document.getElementById('exampleCardNumber').addEventListener('hpc.cardBrand', function (e) {
const brand = e.detail.cardBrand;
const iconContainer = document.getElementById('card-brand-icon');
if (brand) {
iconContainer.textContent = brand;
iconContainer.style.display = 'block';
} else {
iconContainer.style.display = 'none';
}
});
hpc.initializationComplete
Dispatched when the component has finished loading its iframe and is fully initialized. This event fires once per configured field, asynchronously after the orchestrator constructor returns.
The detail object is empty — the event itself signals readiness.
Example usage — tracking initialization across all fields:
const fields = ['exampleCardNumber', 'exampleExpiryDate', 'exampleCVV'];
let initCount = 0;
fields.forEach(function (id) {
document.getElementById(id).addEventListener('hpc.initializationComplete', function () {
initCount++;
if (initCount === fields.length) {
console.log("All HPC components are ready");
// e.g. show the payment form, enable submit button, etc.
}
});
});
The orchestrator constructor returns immediately while iframe loading proceeds asynchronously. Use this event if you need to know when all fields are fully initialized before proceeding (e.g., displaying a hidden payment form).
Events vs Feedback Classes
Both events and feedback classes convey the same underlying state changes. Use feedback classes when you only need visual styling (e.g., changing border colour). Use events when you need to execute logic in response to state changes (e.g., enabling/disabling buttons, updating UI elements, logging analytics).
The two mechanisms are independent — disabling a feedback class by setting it to an empty string does not prevent the corresponding event from firing.
Complete Example
The following demonstrates listening for all four events on each field:
const orchestrator = new OrchestratorMerchant(config);
['exampleCardNumber', 'exampleExpiryDate', 'exampleCVV'].forEach(function (id) {
const container = document.getElementById(id);
// Initialization complete — fires once when the iframe is ready
container.addEventListener('hpc.initializationComplete', function () {
console.log(id, "initialized and ready for input");
});
// Validation state changes
container.addEventListener('hpc.validation', function (e) {
console.log(id, "validation:", e.detail.validation);
});
// Focus state changes
container.addEventListener('hpc.focus', function (e) {
console.log(id, "focused:", e.detail.focus);
});
// Card brand detection (only meaningful for cardNumber field)
if (id === 'exampleCardNumber') {
container.addEventListener('hpc.cardBrand', function (e) {
console.log("Detected brand:", e.detail.cardBrand || "Unknown");
});
}
});