Who this is for. The front-end developer putting a payment element on a form, or adding their own callbacks to one. Setting the element up, and what the server does with the payment, is on Taking payments.
The file
Served by every site at /assets/forms/js-payment-element.js. Each provider's code is a separate file it fetches the first time that provider is shown, so a form offering only Stripe never downloads PayPal's. Load it in the form layout with the page's nonce, after js-forms.js on a JS-model form (the snippet). It sets itself up once, when the page has loaded or at once if it arrives later.
The markup it binds to
The payment element renders this markup; a layout that prints its own must keep it.
| Markup | Role |
|---|---|
[data-payment-provider] | One block per offered method: stripe, paypal, paypal-donate or mock-pay. Any other value is ignored |
data-payment-method-id, data-element-name, data-form-id | On the block: the payment method record, the element's name in the submission, the form |
data-amounts, data-allow-custom-amount, data-currency | The preset amounts (a JSON list), whether a typed amount is allowed, and the currency |
data-publishable-key; data-test-mode | Stripe's publishable key; PayPal's sandbox switch |
.payment-amount-selector | Where the amount buttons and the custom amount field are drawn |
#stripe-elements-{payment method id} | Where Stripe's card field is mounted; required for Stripe |
.payment-method-name | The method's label, used for its tab |
.payment-error | Where the provider's own messages appear, such as a declined card |
.payment-billing-address | The billing address fields, named {element}[billingAddress][{field}] |
Several methods become tabs. With more than one block, the script draws a tab list before the first (ul.nav.nav-tabs of button.nav-link, Bootstrap's classes) and shows one block at a time. Switching tabs tears the previous provider down and starts the new one.
On a JS-model form
When it starts, the script rewrites two attributes of the .coredna-js-form container, after noting the names that were there:
data-submit-modifier-callbackbecomescorednaJsFormPaymentModifier;data-submit-result-callbackbecomescorednaJsFormPaymentResult.
js-forms.js reads those attributes when it needs them, so from then on it calls the payment script's functions, which call yours.
Before sending, the modifier waits for the active provider to be ready, asks it for the payment data and merges it into the body under the element's name: for Stripe, {"paymentMethodId": …, "confirmationToken": …, "amount": …}, plus billingAddress from the address fields. If the provider fails (a card Stripe will not tokenise), its message appears in .payment-error, the submit stops, and js-forms.js shows "Payment processing failed." in the step's .submit-error-message. Then it calls the modifier the markup named, if any, with the merged data. Your modifier cannot cancel the submit here: what it returns replaces the data only when it is truthy; anything else sends the merged data.
When the answer arrives, the result function looks at it first:
| Answer | The script |
|---|---|
redirectUrl in the body (a 202) | Sends the browser there, for a provider that pays off-site |
paypalDonateConfig in the body (a 202) | Hands it to PayPal Donate, which draws PayPal's button. When the payer finishes there, it goes to the configuration's success URL, or shows the result step. The submission completes later, when PayPal's notification reaches the site |
| Anything else | Calls the result callback the markup named, and returns its answer to js-forms.js; with none, lets js-forms.js handle it |
That last row matters: js-forms.js needs this callback to show an error, so a payment form still needs the result callback from Validation, and its attribute must be in the markup when the page loads, since the script reads the names only once.
On a page-per-step form
There are no callbacks to take over. Stripe and Mock Pay catch the form's own submit, get their token, add it and the amount to the form as hidden fields named after the element, and submit the form again.
PayPal Donate, once the payer has finished on PayPal, asks the submission's status every two seconds, up to thirty times. When it turns complete, the script adds _token and _method=PUT to the form and submits it, continuing the stored submission. If it never does, the payer is told the donation was received but its confirmation is taking longer than expected.
Notes
- Mock Pay reports every payment as made and takes no money. Keep it off live forms (Taking payments).
- Reaching the result step does not mean the money is in: a PayPal Donate submission completes when PayPal's notification arrives. Act on the submission's
Completedevent. - The answer statuses (200, 202, 207, 422) are those of the submission route.