A little library that will help you manipulate Shopify´s Checkout via JS.
IMPORTANT: Shopify Plus is needed. The resulting JS needs to be included in checkout.liquid file which is only available to Shopify Plus stores.
Please refer to each version branch in case you are using a previous verions.
Important: V0.2.0 has breaking changes.
v0.1.0: https://github.com/adearriba/ShopifyCheckoutJS/tree/v0.1.0
npm i @adearriba/shopify-checkout
The $checkout object is created to help with the different tasks manipulating Shopify´s checkout page.
To register handlers for common events, you can use the $checkout.on(event, callback) function.
import { $checkout } from '@adearriba/shopify-checkout/checkout.js';
$checkout.on('load', (e) => { console.log(e); })
$checkout.on('load:information', function(e) {
console.log(e);
})
$checkout.on('error', function(e) {
console.trace();
})
Loading events
This are events related to loading or changing a page/step during the checkout process:
|Event name|Descripcion|
|---|---|
|continue|Triggers whenever any of any checkout pages are submitted.|
|load|This is triggered for convenience in every Shopify´s page:load or page:change event.|
|load:information|Information step is loaded|
|load:shipping|Shipping step is loaded. The event.detail object contains the shipping methods shown in the page.|
|load:payment|Payment step is loaded. The event.detail object contains the payment methods shown in the page.|
|load:processing|Processing page is loaded|
|load:thankyou|Thank you page is loaded|
|load:orderstatus|Order status page is loaded|
|load:stockproblems|Stock problems page is loaded. The event.detail object contains a list of name and variant of the products shown in the page.|
Interactive events
This are events related to interactions with the UI.
| Event name | Descripcion |
|---|---|
| shippingmethod:changed | When a shipping method is selected. The event.detail contains the shipping method object. |
| paymentmethod:changed | When a payment method is selected. The event.detail contains the payment method object. |
| component:changed | When a component's value changes. The event.detail contains the component that changed. |
| field:changed | When a field's value changes. The event.detail contains the field that changed. Not all Fields are components so this is a special type of InputComponent. |
Other events
| Event name | Descripcion |
|---|---|
| error | When an exception is catch inside a callback of any triggered event |
| field:created | When a field is created. The field reference is inside the event.detail property. |
| field:removed | When a field is removed. The field reference is inside the event.detail property. |
Insert components into the DOM
Components can be inserted before or after another components. Here an example with fields, which are a specific type of component. Below you'll find an example for sections.
$checkout.fields["checkout_billing_address_phone"].insertBefore(field);
$checkout.fields["checkout_billing_address_last_name"].insertAfter(field);
Watch for changes in components
When a component changes, the checkout:component:changed event triggers. Note: In case of fields, a checkout:field:changed event triggers. For a shorthand, instead of remembering the name of the event, you can use onValueChanged(callback) for both components and fields. At the same time, you can also use on('changed', callback).
field.onValueChanged(function(event){
console.log(event);
});
field.on('changed', function(event){
console.log(event);
});
component.onValueChanged(function(event){
console.log(event);
});
component.on('changed', function(event){
console.log(event);
});
In Shopify's checkout, you'll encounter different sections within a page. In case you want to create a new section for an additional form or separate controllers, you can do so.
Get a section that already exists
//always import the corresponding component
import {SectionComponent} from '@adearriba/shopify-checkout/checkout';
//Using a css selector, you can create a reference to an existing section
let shippingFormSection = new SectionComponent({selector: '.section--shipping-address'});
Create a new section and add it before/after another one
import {SectionComponent} from '@adearriba/shopify-checkout/checkout';
//Create a new Section component
let section = new SectionComponent({name: 'shipping-method', title: 'Shipping method'});
//Add the section before or after the previous reference
shippingFormSection.insertBefore(section);
shippingFormSection.insertAfter(section);
Create a radiobox in a section
//Import both components together
import {SectionComponent, RadioContentBoxComponent} from '@adearriba/shopify-checkout/checkout';
//Create a new RadioContentBoxComponent
var radioBox = new RadioContentBoxComponent({name: 'RadioContentBox' });
//Create an option using innerHTML instead of a text label
let option1 = {
htmlFor: 'shipping',
value: 'shipping',
innerHTML: '<svg aria-hidden="true" class="icon-svg icon-svg--size-18 icon-svg--inline-before" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M17.816 14c-.415-1.162-1.514-2-2.816-2-1.302 0-2.4.838-2.816 2H12v-4h6v4h-.184zM15 16c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zM5 16c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zM2 4h8v10H7.816C7.4 12.838 6.302 12 5 12c-1.302 0-2.4.838-2.816 2H2V4zm13.434 1l1.8 3H12V5h3.434zm4.424 3.485l-3-5C16.678 3.185 16.35 3 16 3h-4c0-.552-.448-1-1-1H1c-.552 0-1 .448-1 1v12c0 .552.448 1 1 1h1.185C2.6 17.162 3.698 18 5 18s2.4-.838 2.816-2h4.37c.413 1.162 1.512 2 2.814 2s2.4-.838 2.816-2H19c.552 0 1-.448 1-1V9c0-.18-.05-.36-.142-.515z" fill-rule="evenodd"></path></svg>Shipping'};
//Using a text label
let option2 = {label: 'Pickup in Store', htmlFor: 'pickup', value: 'pickup'};
//Add options to RadioContentBoxComponent
radioBox.addOption(option1);
radioBox.addOption(option2);
//Add the RadioContentBoxComponent to the previous section
section.addContent(radioBox);
//Insert the new section before the existing shippingFormSection
shippingFormSection.insertBefore(section);
Result
Get selected value
console.log(radioBox.value);
Fields are a special kind of components with additional functionality. Different types of fields can be created. Whenever a field is created with its constructor, it is added to the $checkout.fields dictionary with its key being 'checkout_attributes_' + ${name}.
For Shopify´s original form fields, they are registered in the dictionary with the input´s id. For example, the address line 1 would be:
//Shopify´s form fields using their id
$checkout.fields["checkout_billing_address_address1"]
//$checkout created fields using the field´s name given upon creation
$checkout.fields["checkout_attributes_fieldName"]
Get input value
console.log(field.value);
field.value = '';
Add an error message and color
You can add a red border to the input and a message below it. The message can contain HTML elements in it.
field.showError('Testing error message with <b>bold</b> text!');
Remove errors
Remove the error state.
field.removeError();
Create TextFields
import {TextField} from '@adearriba/shopify-checkout/checkout';
var field = new TextField({
name:'dni',
//Optional properties
type: 'text',
placeholder:'DNI',
label:'DNI',
size: 30,
defaultValue: '',
tooltip: 'Content of the tooltip'
});
//Accesible also from $checkout.fields
console.log($checkout.fields["checkout_attributes_dni"]);
Add tooltip to field
field.addTooltip('The content of the tooltip');
Adding it to the DOM
$checkout.fields["checkout_billing_address_phone"].insertBefore(field);
Create Checkbox
import {CheckboxField} from '@adearriba/shopify-checkout/checkout';
var field = new CheckboxField({
name:'dni',
//Optional properties
label:'DNI',
checked: true, // default: false
});
Get and set checked state
field.checked = true;
console.log(field.checked);
Create a dropdown/select
import {DropdownField} from '@adearriba/shopify-checkout/checkout';
var select = new DropdownField({
name: 'selections',
options: [
{ text: 'option1', value: 1 },
{ text: 'option2', value: 2 },
{ text: 'option3', value: 3 },
{ text: 'option4', value: 4 },
{ text: 'option5', value: 5 },
],
//optional properties
defaultValue: 'First & disabled Option',
label:'Selections',
});
Get selected value
console.log(select.value);
When the load:shipping event is triggered, the event.detail object contains the shipping methods shown to the customer.
You can add a little description beneath the shipping method name. This accepts HTML so it can be more flexible.
$checkout.on('load:shipping', e => {
let shippingMethods = e.detail.shippingMethods;
shippingMethods[0].addDescription('Shipping by <b>UPS</b>')
});
...
shippingMethods[0].checked = true;
console.log(shippingMethods[0].checked);
...
The shipping method object has direct access to the shipping rate and subtotal price (lineitems + shipping rate). More data can be obtained from the methodData property.
console.log(shippingMethods[0].shippingRate);
console.log(shippingMethods[0].subtotalPrice);
console.log(shippingMethods[0].methodData);
When the load:payment event is triggered, the event.detail object contains the payment methods shown to the customer.
You can add a little description in the content box beneath the payment method radio button. This accepts HTML so it can be more flexible.
$checkout.on('load:payment', e => {
let paymentMethods = e.detail.paymentMethods;
paymentMethods[1].addDescription('Payment using <b>Paypal</b>')
});
...
paymentMethods[0].checked = true;
console.log(paymentMethods[0].checked);
...
The payment method object has direct access to the gateway ID and gateway name. More data can be obtained from the methodData property.
console.log(paymentMethods[0].gatewayId);
console.log(paymentMethods[0].gatewayName);
console.log(paymentMethods[0].methodData);
$ claude mcp add ShopifyCheckoutJS \
-- python -m otcore.mcp_server <graph>