# Subscribe to Card Field events (/expanded/card-field-events)

Learn how to subscribe to credit and debit card field events. Customize your form by using event listeners for advanced payment processing.



> **Warning:** **Information:** This JavaScript SDK documentation uses the `CardFields` component. If you are integrated with the legacy `HostedFields` component, see [Hosted Field Events](/expanded/card-field-events/).

## Subscribe to events [#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 [#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 [#supported-input-event-callbacks]

You can pass the following callbacks to the `inputEvents` object:

| Event Name             | Description                                 |
| ---------------------- | ------------------------------------------- |
| `onChange`             | Called when the input in any field changes. |
| `onFocus`              | Called when any field gets focus.           |
| `onBlur`               | Called when any field loses focus.          |
| `onInputSubmitRequest` | Called when a payer submits the field.      |

### Example: inputEvents into parent component [#example-inputevents-into-parent-component]

Pass the `inputEvents` object into the parent `CardFields` component:

```text lineNumbers
const cardField = paypal.CardFields({
          inputEvents: {
              onChange: function(data) => {
                  // Do something when an input changes
              },
              onFocus: function(data) => {
                  // Do something when a field gets focus
              },
              onBlur: function(data) => {
                  // Do something when a field loses focus
              }
              onInputSubmitRequest: function(data) => {
                  if (data.isFormValid) {
                      // Submit the card form for the payer
                  } else {
                      // Inform payer that some fields are not valid
                  }
              }
          }
      })
```

### Example: inputEvents into individual component [#example-inputevents-into-individual-component]

Pass the `inputEvents` object into each individual field component:

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const nameField = cardField.NameField({
             inputEvents: {
              onChange: function(data) => {
                  // Do something when the input of only the name field changes
              },
              onFocus: function(data) => {
                  // Do something when only the name field gets focus
              },
              onBlur: function(data) => {
                  // Do something when only name field loses focus
              }
              onInputSubmitRequest: function(data) => {
                  if (data.isFormValid) {
                      // Submit the card form for the payer
                  } else {
                      // Inform payer that some fields are not valid
                  }
              }
          }
      });
```

### Sample state object [#sample-state-object]

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

```text lineNumbers
data: {
          cards: [{code: {name: 'CVV', size: 3}, niceType: "Visa", type: "visa"}]
          emittedBy: "number", // Not returned for getState()
          isFormValid: false,
          errors: ["INVALID_CVV"]
          fields: {
              cardCvvField: {
                  isFocused: false,
                  isEmpty: true,
                  isValid: false,
                  isPotentiallyValid: true,
              },
              cardNumberField: {
                  isFocused: true,
                  isEmpty: false,
                  isValid: false,
                  isPotentiallyValid: true,
              },
              cardNameField: {
                  isFocused: false,
                  isEmpty: true,
                  isValid: false,
                  isPotentiallyValid: true,
              },
              cardExpiryField: {
                  isFocused: false,
                  isEmpty: true,
                  isValid: false,
                  isPotentiallyValid: true,
              },
          },
      }
```

### Validate individual fields [#validate-individual-fields]

Validate individual fields when an input event occurs:

```text lineNumbers
const cardFields = paypal.CardFields({/* options */});
let cardContainer = document.getElementById("#card-number-field-container")
const cardNumberField = cardFields.NumberField({
          // Add valid or invalid class when the validation changes on the field
          inputEvents: {
              onChange: (data) => {
                  cardContainer.className = data.fields.cardNumberField.isValid ? 'valid' : 'invalid';
              }
          }
      })
```

### Validate entire card form [#validate-entire-card-form]

Validate an entire card form when an input event occurs:

```text lineNumbers
const formContainer = document.getElementById("form-container")
const cardFields = paypal.CardFields({
          inputEvents: {
              onChange: (data) => {
                  formContainer.className = data.isFormValid ? 'valid' : 'invalid'
              }
          }
      });
```

## Methods on parent card fields [#methods-on-parent-card-fields]

The following methods are supported on parent card fields:

* `getState()`
* `isEligible()`
* `submit()`

**getState()*&#x2A; -> &#x2A;*\{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

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
      // ...
      // Render the card fields
      // ...
      cardFields.getState().then((data) => {
          // Submit only if the current
          // state of the form is valid
          if (data.isFormValid) {
              cardFields.submit().then(() => {
                  //Submit success
              }).catch((error) => {
                  //Submit error
              });
          }
      });
```

**isEligible()*&#x2A; -> &#x2A;*\{Boolean}**

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

Example

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
if (cardFields.isEligible()) {
  cardFields.NumberField().render("#card-number-field-container");
  cardFields.CVVField().render("#card-cvv-field-container");
  // ...
}
```

**submit()*&#x2A; -> &#x2A;*\{promise | void}**

Submits payment information.

Example

```text lineNumbers
// Add click listener to your submit button
// and call the submit function on the CardField component
multiCardFieldButton.addEventListener("click", () => {
  cardField.submit().then(() => {
    console.log("Card Fields submit");
  }).catch((err) => {
    console.log("There was an error with card fields: ", err);
  });
});
```

### Methods on individual card fields [#methods-on-individual-card-fields]

The following methods are supported on individual card fields:

* `addClass()`
* `clear()`
* `focus()`
* `removeAttribute()`
* `removeClass()`
* `render()`
* `setAttribute()`
* `setMessage()`
* `close()`

**addClass()*&#x2A; -> &#x2A;*\{promise | void}**

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

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const numberField = cardField.NumberField(/* options */)
numberField.addClass("purple");
numberField.render(cardNumberContainer);
```

**clear()*&#x2A; -> &#x2A;*\{void}**

Clears the value of the field.

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const nameField = cardField.NameField(/* options */);
nameField.render(cardNameContainer);
nameField.clear();
```

**focus()*&#x2A; -> &#x2A;*\{void}**

Focuses the field.

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const nameField = cardField.NameField(/* options */)
nameField.render(cardNameContainer);
nameField.focus();
```

**removeAttribute()*&#x2A; -> &#x2A;*\{promise | void}**

Removes an attribute from a field where called.

### Supported attributes to remove [#supported-attributes-to-remove]

You can remove the following attributes with `removeAttribute`:

* `aria-invalid`
* `aria-required`
* `disabled`
* `placeholder`

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const numberField = cardField.NumberField(/* options */)
numberField.render(cardNumberContainer);
numberField.removeAttribute("placeholder");
```

**removeClass()*&#x2A; -> &#x2A;*\{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.

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const numberField = cardField.NumberField(/* options */)
numberField.render(cardNumberContainer);
numberField.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.

```text lineNumbers
const cardNumberContainer = document.getElementById("card-number-field-container");
const cardField = paypal.CardFields(/* options */)
cardField.NumberField(/* options */).render(cardNumberContainer);
// OR use a selector string
cardField.NumberField(/*options*/).render("#card-number-field-container")
```

**setAttribute()*&#x2A; -> &#x2A;*\{promise | void}**

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

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const nameField = cardField.NameField(/* options */)
nameField.setAttribute("placeholder", "Enter your full name");
nameField.render(cardNameContainer);
```

**setMessage()*&#x2A; -> &#x2A;*\{void}**

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

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const nameField = cardField.NameField(/* options */)
nameField.render(cardNameContainer);
nameField.setMessage("Enter your full name");
```

**close()*&#x2A; -> &#x2A;*\{promise | void}**

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

```text lineNumbers
const cardField = paypal.CardFields(/* options */)
const nameField = cardField.NameField(/* options */)
nameField.render(cardNameContainer);
// Call this to tear down nameField
nameField.close();
```

## Type definitions [#type-definitions]

* [cardSecurityCode](/expanded/card-field-events#cardsecuritycode)
* [cardType](/expanded/card-field-events#cardtype)
* [cardFieldData](/expanded/card-field-events#cardfielddata)
* [stateObject](/expanded/card-field-events#stateobject)

### cardSecurityCode [#cardsecuritycode]

Information about the security code for a card.

| Property | Type   | Description                                                                       |
| -------- | ------ | --------------------------------------------------------------------------------- |
| `name`   | string | The name of a security code for a card. Valid values are `CVV`, `CID`, and `CVC`. |
| `size`   | number | The expected length of the security code, typically `3` or `4` digits.            |

### cardType [#cardtype]

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

| Property   | Type                      | Description                                                                                                                                                          |
| ---------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`     | string                    | The code-readable card type. Valid values are: `american-express``diners-club``discover``jcb``maestro``mastercard``unionpay``visa``elo``hiper`, `hipercard`          |
| `code`     | object `cardSecurityCode` | Contains 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. |
| `niceType` | string                    | The human-readable card type. Valid values are: `American Express``Diner Club``discover``JCB``Maestro``Mastercard``UnionPay``Visa``Elo``Hiper`,`Hipercard`           |

### cardFieldData [#cardfielddata]

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

| Property             | Type    | Description                                                                                                                                                                                         |
| -------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `isFocused`          | boolean | Shows whether the input field is currently focused.                                                                                                                                                 |
| `isEmpty`            | boolean | Shows whether the user has entered a value in the input.                                                                                                                                            |
| `isPotentiallyValid` | boolean | Shows 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. |
| `isValid`            | boolean | Shows whether the input is valid and can be submitted.                                                                                                                                              |

### stateObject [#stateobject]

| Property      | Type                | Description                                                                                                                                                                                                                 |
| ------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cards`       | array of `cardType` | Returns an array of potential cards. If the card type has been determined, the array contains only one card.                                                                                                                |
| `emittedBy`   | string              | The name of the field associated with an event. `emittedBy` is not included if returned by `getState`. Valid values are `"name"`,`"number"`, `"cvv"`, and `"expiry"`.                                                       |
| `errors`      | array               | array of card fields that are currently not valid. Potential values are `"INELIGIBLE_CARD_VENDOR"`,`"INVALID_NAME"`, `"INVALID_NUMBER"`, `"INVALID_EXPIRY"` or `"INVALID_CVV"`.                                             |
| `isFormValid` | boolean             | Shows whether the form is valid.                                                                                                                                                                                            |
| `fields`      | object              | Contains 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 [#full-example]

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

```text lineNumbers
<html>
          <head>
              <meta charset="UTF-8">
              <title>Checkout Page</title>
          </head>
          <body>
              <div id="checkout-form">
               <div id="card-name-field-container"></div>
               <div id="card-number-field-container"></div>
               <div id="card-expiry-field-container"></div>
               <div id="card-cvv-field-container"></div>
               <button id="multi-card-field-button" type="button">Pay now with Card Fields</button>
              </div>
          </body>
            <script src="https://www.paypal.com/sdk/js?client-id=<your-client-id>&components=card-fields"></script>
            <script>
             // Custom styles object (optional)
              const styleObject = {
                  input: {
                      "font-size": "16 px",
                      "font-family": "monospace",
                      "font-weight": "lighter",
                      color: "blue",
                  },
                  ".invalid": {
                  color: "purple",
                  },
                  ":hover": {
                      color: "orange",
                  },
                  ".purple": {
                      color: "purple",
                  },
              };
              // Create the card fields component and define callbacks
              const cardField = paypal.CardFields({
                  style: styleObject,
                  createOrder: function (data, actions) {
                      return fetch("/api/paypal/order/create/", {
                      method: "post",
                      })
                      .then((res) => {
                          return res.json();
                      })
                      .then((orderData) => {
                          return orderData.id;
                      });
                  },
                  onApprove: function (data, actions) {
                      const { orderID } = data;
                      return fetch('/api/paypal/orders/${orderID}/capture/', {
                      method: "post",
                      })
                      .then((res) => {
                          return res.json();
                      })
                      .then((orderData) => {
                          // Redirect to success page
                      });
                  },
                  inputEvents: {
                      onChange: function (data) {
                          // Handle a change event in any of the fields
                      },
                      onFocus: function(data) {
                          // Handle a focus event in any of the fields
                      },
                      onBlur: function(data) {
                          // Handle a blur event in any of the fields
                      },
                      onInputSubmitRequest: function(data) {
                          // Handle an attempt to submit the entire card form
                          // while focusing any of the fields
                      }
                  },
              });
              // Define the container for each field and the submit button
              const cardNameContainer = document.getElementById("card-name-field-container"); // Optional field
              const cardNumberContainer = document.getElementById("card-number-field-container");
              const cardCvvContainer = document.getElementById("card-cvv-field-container");
              const cardExpiryContainer = document.getElementById("card-expiry-field-container");
              const multiCardFieldButton = document.getElementById("multi-card-field-button");
              // Render each field after checking for eligibility
              if (cardField.isEligible()) {
                  const nameField = cardField.NameField();
                  nameField.render(cardNameContainer);
                  const numberField = cardField.NumberField();
                  numberField.render(cardNumberContainer);
                  const cvvField = cardField.CVVField();
                  cvvField.render(cardCvvContainer);
                  const expiryField = cardField.ExpiryField();
                  expiryField.render(cardExpiryContainer);
                  // Add click listener to the submit button and call the submit function on the CardField component
                  multiCardFieldButton.addEventListener("click", () => {
                      cardField
                      .submit()
                      .then(() => {
                          // Handle a successful payment
                      })
                      .catch((err) => {
                          // Handle an unsuccessful payment
                      });
                  });
              }
            </script>
      </html>
```

## Next steps & customizations [#next-steps--customizations]

> **Info:** Card field properties
>
> Customize Card field properties.

> **Info:** Style card fields
>
> Change the layout, width, height, and outer styling of the card fields.

> **Info:** JavaScript SDK
>
> Customize your integration with script config parameters.
