Subscribe to card field events for direct merchants

DocsCurrentAdvancedLast updated: April 9th 2024, @ 12:28:25 pm


Important: This is version 2 of the card field events guide for direct merchants. Version 1 is a legacy integration.

Subscribe to events

Subscribe to advanced credit and debit card payment events using an event listener. Event listeners can help you update the UI of your form based on the state of the fields.

inputEvents

You can pass an inputEvents object into a parent cardField component or each card field individually.

Pass an inputEvents object to the parent cardField component to apply the object to every field.

Pass an inputEvents object to an individual card field to apply the object to that field only. This overrides any object passed through a parent component.

Supported input event callbacks

You can pass the following callbacks to the inputEvents object:

Event NameDescription
onChangeCalled when the input in any field changes.
onFocusCalled when any field gets focus.
onBlurCalled when any field loses focus.
onInputSubmitRequestCalled when a payer submits the field.

Example: inputEvents into parent component

Pass the inputEvents object into the parent CardFields component:

1const cardField = paypal.CardFields({
2 inputEvents: {
3 onChange: function(data) => {
4 // Do something when an input changes
5 },
6 onFocus: function(data) => {
7 // Do something when a field gets focus
8 },
9 onBlur: function(data) => {
10 // Do something when a field loses focus
11 }
12 onInputSubmitRequest: function(data) => {
13 if (data.isFormValid) {
14 // Submit the card form for the payer
15 } else {
16 // Inform payer that some fields are not valid
17 }
18 }
19 }
20 })

Example: inputEvents into individual component

Pass the inputEvents object into each individual field component:

1const cardField = paypal.CardFields(/* options */)
2const nameField = cardField.NameField({
3 inputEvents: {
4 onChange: function(data) => {
5 // Do something when the input of only the name field changes
6 },
7 onFocus: function(data) => {
8 // Do something when only the name field gets focus
9 },
10 onBlur: function(data) => {
11 // Do something when only name field loses focus
12 }
13 onInputSubmitRequest: function(data) => {
14 if (data.isFormValid) {
15 // Submit the card form for the payer
16 } else {
17 // Inform payer that some fields are not valid
18 }
19 }
20 }
21 });

Sample state object

Each of the event callbacks returns a state object similar to the following example:

1data: {
2 cards: [{code: {name: 'CVV', size: 3}, niceType: "Visa", type: "visa"}]
3 emittedBy: "number", // Not returned for getState()
4 isFormValid: false,
5 errors: ["INVALID_CVV"]
6 fields: {
7 cardCvvField: {
8 isFocused: false,
9 isEmpty: true,
10 isValid: false,
11 isPotentiallyValid: true,
12 },
13 cardNumberField: {
14 isFocused: true,
15 isEmpty: false,
16 isValid: false,
17 isPotentiallyValid: true,
18 },
19 cardNameField: {
20 isFocused: false,
21 isEmpty: true,
22 isValid: false,
23 isPotentiallyValid: true,
24 },
25 cardExpiryField: {
26 isFocused: false,
27 isEmpty: true,
28 isValid: false,
29 isPotentiallyValid: true,
30 },
31 },
32 }

Validate individual fields

Validate individual fields when an input event occurs:

1const cardFields = paypal.CardFields({/* options */});
2let cardContainer = document.getElementById("#card-number-field-container")
3const cardNumberField = cardFields.NumberField({
4 // Add valid or invalid class when the validation changes on the field
5 inputEvents: {
6 onChange: (data) => {
7 cardContainer.className = data.fields.cardNumberField.isValid ? 'valid' : 'invalid';
8 }
9 }
10 })

Validate entire card form

Validate an entire card form when an input event occurs:

1const formContainer = document.getElementById("form-container")
2const cardFields = paypal.CardFields({
3 inputEvents: {
4 onChange: (data) => {
5 formContainer.className = data.isFormValid ? 'valid' : 'invalid'
6 }
7 }
8 });

Methods on parent card fields

The following methods are supported on parent card fields:

  • getState()
  • isEligible()
  • submit()

getState() -> {promise | void}

Returns a promise that resolves into a stateObject. Includes the state of all fields, possible card types, and an array of errors.

Example

1const cardField = paypal.CardFields(/* options */)
2 // ...
3 // Render the card fields
4 // ...
5 cardFields.getState().then((data) => {
6 // Submit only if the current
7 // state of the form is valid
8 if (data.isFormValid) {
9 cardFields.submit().then(() => {
10 //Submit success
11 }).catch((error) => {
12 //Submit error
13 });
14 }
15 });

isEligible() -> {Boolean}

Checks if a cardField instance can render based on configuration and business rules.

Example

1const cardField = paypal.CardFields(/* options */)
2if (cardFields.isEligible()) {
3 cardFields.NumberField().render("#card-number-field-container");
4 cardFields.CVVField().render("#card-cvv-field-container");
5 // ...
6}

submit() -> {promise | void}

Submits payment information.

1// Add click listener to your submit button
2// and call the submit function on the CardField component
3multiCardFieldButton.addEventListener("click", () => {
4 cardField.submit().then(() => {
5 console.log("Card Fields submit");
6 }).catch((err) => {
7 console.log("There was an error with card fields: ", err);
8 });
9});

Methods on individual card fields

The following methods are supported on individual card fields:

  • addClass()
  • clear()
  • focus()
  • removeAttribute()
  • removeClass()
  • render()
  • setAttribute()
  • setMessage()
  • close()

addClass() -> {promise | void}

Adds a class to a field. Used to update field styles when events occur elsewhere during checkout.

1const cardField = paypal.CardFields(/* options */)
2const numberField = cardField.NumberField(/* options */)
3numberField.addClass("purple");
4numberField.render(cardNumberContainer);

clear() -> {void}

Clears the value of the field.

1const cardField = paypal.CardFields(/* options */)
2const nameField = cardField.NameField(/* options */);
3nameField.render(cardNameContainer);
4nameField.clear();

focus() -> {void}

Focuses the field.

1const cardField = paypal.CardFields(/* options */)
2const nameField = cardField.NameField(/* options */)
3nameField.render(cardNameContainer);
4nameField.focus();

removeAttribute() -> {promise | void}

Removes an attribute from a field where called.

Supported attributes to remove

You can remove the following attributes with removeAttribute:

  • aria-invalid
  • aria-required
  • disabled
  • placeholder
1const cardField = paypal.CardFields(/* options */)
2const numberField = cardField.NumberField(/* options */)
3numberField.render(cardNumberContainer);
4numberField.removeAttribute("placeholder");

removeClass() -> {promise | void}

Pass the class name as a string in removeClass to remove a class from a field. Used to update field styles when events occur elsewhere in the checkout flow.

1const cardField = paypal.CardFields(/* options */)
2const numberField = cardField.NumberField(/* options */)
3numberField.render(cardNumberContainer);
4numberField.removeClass("purple");

render() -> {promise | void}

Renders the individual card fields to the DOM for checkout.

Pass the HTML element reference or CSS selector string for the input field.

1const cardNumberContainer = document.getElementById("card-number-field-container");
2const cardField = paypal.CardFields(/* options */)
3cardField.NumberField(/* options */).render(cardNumberContainer);
4// OR use a selector string
5cardField.NumberField(/*options*/).render("#card-number-field-container")

setAttribute() -> {promise | void}

Sets the supported attributes and values of a field. Pass in attributes and values as strings.

1const cardField = paypal.CardFields(/* options */)
2const nameField = cardField.NameField(/* options */)
3nameField.setAttribute("placeholder", "Enter your full name");
4nameField.render(cardNameContainer);

setMessage() -> {void}

Sets a message on a field for screen readers. Pass the message as a string in setMessage.

1const cardField = paypal.CardFields(/* options */)
2const nameField = cardField.NameField(/* options */)
3nameField.render(cardNameContainer);
4nameField.setMessage("Enter your full name");

close() -> {promise | void}

Tears down the card field. Use this method to cleanly dispose of the component created by render.

1const cardField = paypal.CardFields(/* options */)
2const nameField = cardField.NameField(/* options */)
3nameField.render(cardNameContainer);
4// Call this to tear down nameField
5nameField.close();

Type definitions

cardSecurityCode

Information about the security code for a card.

PropertyTypeDescription
namestringThe name of a security code for a card. Valid values are CVV, CID, and CVC.
sizenumberThe expected length of the security code, typically 3 or 4 digits.

cardType

Information about the card type sent in the cards array as a part of the stateObject.

PropertyTypeDescription
typestringThe code-readable card type. Valid values are:
  • american-express
  • diners-club
  • discover
  • jcb
  • maestro
  • mastercard
  • unionpay
  • visa
  • elo
  • hiper, hipercard
codeobject cardSecurityCodeContains data about the card brand's security code requirements. For example, on a Visa card, the CVV is 3 digits. On an American Express card, the CID is 4 digits.
niceTypestringThe human-readable card type. Valid values are:
  • American Express
  • Diner Club
  • discover
  • JCB
  • Maestro
  • Mastercard
  • UnionPay
  • Visa
  • Elo
  • Hiper,Hipercard

cardFieldData

Field data for card payments is sent for each card field in the stateObject.

PropertyTypeDescription
isFocusedbooleanShows whether the input field is currently focused.
isEmptybooleanShows whether the user has entered a value in the input.
isPotentiallyValidbooleanShows whether the current input can be valid. For example, if a payer enters 41 for the card number, the input can become valid. However, if the payer enters 4x, the input can't become valid.
isValidbooleanShows whether the input is valid and can be submitted.

stateObject

PropertyTypeDescription
cardsarray of cardTypeReturns an array of potential cards. If the card type has been determined, the array contains only one card.
emittedBystringThe name of the field associated with an event. emittedBy is not included if returned by getState. Valid values are "name","number", "cvv", and "expiry".
errorsarrayarray of card fields that are currently not valid. Potential values are "INELIGIBLE_CARD_VENDOR","INVALID_NAME", "INVALID_NUMBER", "INVALID_EXPIRY" or "INVALID_CVV".
isFormValidbooleanShows whether the form is valid.
fieldsobjectContains data about the field in the context of the event. Valid values are "cardNameField", "cardCvvField", "cardNumberField" and "cardExpiryField". Each of these keys contain an object of type cardFieldData.

Full example

The following sample shows how a full hosted card fields script might appear in HTML:

1<html>
2 <head>
3 <meta charset="UTF-8">
4 <title>Checkout Page</title>
5 </head>
6 <body>
7 <div id="checkout-form">
8 <div id="card-name-field-container"></div>
9 <div id="card-number-field-container"></div>
10 <div id="card-expiry-field-container"></div>
11 <div id="card-cvv-field-container"></div>
12 <button id="multi-card-field-button" type="button">Pay now with Card Fields</button>
13 </div>
14 </body>
15 <script src="https://www.paypal.com/sdk/js?client-id=<your-client-id>&components=card-fields"></script>
16 <script>
17 // Custom styles object (optional)
18 const styleObject = {
19 input: {
20 "font-size": "16 px",
21 "font-family": "monospace",
22 "font-weight": "lighter",
23 color: "blue",
24 },
25 ".invalid": {
26 color: "purple",
27 },
28 ":hover": {
29 color: "orange",
30 },
31 ".purple": {
32 color: "purple",
33 },
34 };
35 // Create the card fields component and define callbacks
36 const cardField = paypal.CardFields({
37 style: styleObject,
38 createOrder: function (data, actions) {
39 return fetch("/api/paypal/order/create/", {
40 method: "post",
41 })
42 .then((res) => {
43 return res.json();
44 })
45 .then((orderData) => {
46 return orderData.id;
47 });
48 },
49 onApprove: function (data, actions) {
50 const { orderID } = data;
51 return fetch('/api/paypal/orders/${orderID}/capture/', {
52 method: "post",
53 })
54 .then((res) => {
55 return res.json();
56 })
57 .then((orderData) => {
58 // Redirect to success page
59 });
60 },
61 inputEvents: {
62 onChange: function (data) {
63 // Handle a change event in any of the fields
64 },
65 onFocus: function(data) {
66 // Handle a focus event in any of the fields
67 },
68 onBlur: function(data) {
69 // Handle a blur event in any of the fields
70 },
71 onInputSubmitRequest: function(data) {
72 // Handle an attempt to submit the entire card form
73 // while focusing any of the fields
74 }
75 },
76 });
77 // Define the container for each field and the submit button
78 const cardNameContainer = document.getElementById("card-name-field-container"); // Optional field
79 const cardNumberContainer = document.getElementById("card-number-field-container");
80 const cardCvvContainer = document.getElementById("card-cvv-field-container");
81 const cardExpiryContainer = document.getElementById("card-expiry-field-container");
82 const multiCardFieldButton = document.getElementById("multi-card-field-button");
83 // Render each field after checking for eligibility
84 if (cardField.isEligible()) {
85 const nameField = cardField.NameField();
86 nameField.render(cardNameContainer);
87 const numberField = cardField.NumberField();
88 numberField.render(cardNumberContainer);
89 const cvvField = cardField.CVVField();
90 cvvField.render(cardCvvContainer);
91 const expiryField = cardField.ExpiryField();
92 expiryField.render(cardExpiryContainer);
93 // Add click listener to the submit button and call the submit function on the CardField component
94 multiCardFieldButton.addEventListener("click", () => {
95 cardField
96 .submit()
97 .then(() => {
98 // Handle a successful payment
99 })
100 .catch((err) => {
101 // Handle an unsuccessful payment
102 });
103 });
104 }
105 </script>
106 </html>

See also