Integrating Slots
Available slot names
A comprehensive list of all slot names where content can be added.
slot_dynamic_area_guest
slot_dynamic_area_register
slot_option_sign_in
slot_option_register
slot_option_guest
slot_option_selected_sign_in
slot_option_selected_register
slot_option_selected_guest
Styling
The content injected into the slot should come with its own styles as these are not inherited from the parent.
Events
Since slots can be clickable, if content is injected into one of the non-selected option slots, the slotContent
will require an onclick
attribute to dispatch an event that propagates the option click/switch on the checkout side. Make sure the event name matches with the slot name.
element.onclick = () => element.dispatchEvent(new CustomEvent({{slot_name}}, {
bubbles: true,
composed: true
}));
Methods
Within the window.scayleCheckoutFunctions.mutations
object, we expose native checkout methods to be used within the storefront within slots implementation that requires logic such as immediately returning the current state.
signIn: Promise<CheckoutState>
register: Promise<CheckoutState>
setPasswordForCustomerNumber: Promise<CheckoutState>
setBasketItemQuantity: Promise<number | undefined>
removeBasketItem: Promise<CheckoutState>
setCarrierAndShippingOption: Promise<CheckoutState>
setCollectionPoint: Promise<CheckoutState>
setShippingAddress: Promise<AddressSuggestion[] | undefined>
setShippingAddressAsBillingAddress: Promise<CheckoutState>
setBillingAddress: Promise<AddressSuggestion[] | undefined>
setDynamicFields: Promise<CheckoutState>
forceOrderUpdate: Promise<CheckoutState>
getState: Promise<CheckoutState>
setPaymentOption: Promise<CheckoutState>
updatePaymentOption: Promise<any>
addGiftCard: Promise<GiftCard[] | undefined>
removePromotions: Promise<CheckoutState>
removeGiftCard: Promise<CheckoutState>
addVoucher: Promise<CheckoutState>
removeVoucher: Promise<CheckoutState>
addPromotion: Promise<CheckoutState>
removePromotion: Promise<CheckoutState>
removeRecurringPaymentMethod: Promise<CheckoutState>
registerForLoyaltyProgram: Promise<CheckoutState>
setLoyaltyProgram: Promise<CheckoutState>
removeLoyaltyProgram: Promise<CheckoutState>
redeemLoyaltyProgramPoints: Promise<CheckoutState>
unredeemLoyaltyProgramPoints: Promise<CheckoutState>
confirmOrder: Promise<ConfirmOrderResponse>
The full types are listed below within the types section
Types
CheckoutState
{
addressSuggestions?: {
suggestions: Array<{
street: string;
houseNumber?: string;
zipCode?: string;
city: string;
state?: string;
country: { iso2Code: string };
title?: string;
salutationCode?: 'f' | 'm' | 'd' | 'n';
firstName: string;
lastName: string;
additional?: string;
phone?: string;
forwardToCollectionPoint?: boolean;
isOriginal: boolean;
signature: string;
}>;
};
customer?: {
authentication: { data: any; type: string };
data: {
birthDate?: string;
customData?: any;
email: string;
firstName: string;
gender: string;
id: number;
lastName: string;
trackingHash?: string;
publicKey: string;
referenceKey?: string;
title?: string;
type: string;
phone?: { plainText: string };
};
flags?: {
canUpgradeToFullAccount?: boolean;
hasFreeShipping?: boolean;
isGuest: boolean;
hasReturnCosts?: boolean;
isCarrierSelectionBlocked?: boolean;
hasCodPaymentFees?: boolean;
};
groups?: string[];
securityHash?: string;
};
integrations: {
campaigns?: Array<{ isApplicable: boolean; name: string }>;
newsletter: { customerIsConfirmedSubscriber: boolean; enabled: boolean };
promotion?: { codes: { enabled: boolean } };
};
merchants?: Array<{
id: number;
isMarketplaceMerchant: boolean;
legalNotice?: {
city?: string;
country?: { id: number; iso3166Alpha2Code: string; iso3166Alpha3Code: string };
email?: string;
legalName?: string;
managingDirectors?: string;
parentCompanyLegalName?: string;
parentCompanyRegisterNumber?: string;
parentCompanyRegistryCourtCity?: string;
parentCompanyRegistryCourtType?: Record<string, string>;
registerNumber?: string;
registryCourtCity?: string;
registryCourtType?: Record<string, string>;
representative?: string;
shippingMerchantName?: string;
streetWithNumber?: string;
telephone?: string;
vatIds?: Array<{ country?: { id: number; iso3166Alpha2Code: string }; vatId: string }>;
vatId?: string;
zip?: string;
};
}>;
orderOptions?: {
payment?: {
generic: Array<{
paymentOptionKey: string;
paymentOptionProvider: string;
isDisabled: boolean;
configuration?: {
initializationData?: any;
isRecurring?: boolean;
isAutoCapture?: boolean;
deferral?: { autoApplyDeferral: boolean; isSelected: boolean; isSupported: boolean; weeks: number };
fee?: number;
codPaymentFee?: number;
instalments?: Array<{ number: number; isSelected: boolean }>;
public?: { requiresTranslation?: boolean; requiresBrands?: string[] };
};
instalment?: { firstInstalmentValue: number; numberOfInstalments: number; subsequentInstalmentValue: number };
notifications?: Array<{ id?: string; type: 'success' | 'info' | 'warning' | 'error'; text?: string }>;
serviceCosts?: { total: number };
}>;
giftCards?: Array<{
recurringPaymentOptionId: string;
recurringPaymentInformation: { giftCardCode: string; remainingAmount: number };
}>;
recurring?: Array<{
recurringPaymentOptionId: string;
recurringPaymentInformation?: { creditcardBrand?: string; maskedCreditcardNumber?: string; customerEmail?: string };
}>;
};
shipping?: {
carrierChangeAllowed?: boolean;
collectionPointDelivery?: Array<{
carrierGroupKey: string;
carrierKey: string;
deliveryOptionKey: string;
shippingOptionKey: string;
hideDivergingBillingAddress?: boolean;
imageFileName?: string;
collectionPointType?: string;
isDisabled?: boolean;
returnCosts?: { minBruttoOrderValueAfterReturns: number; returnServiceCost: number };
deliveryDate?: string;
deliveryDates?: { maximum: string; minimum: string };
serviceCosts?: { taxAmount: number; taxRate: number; withoutTax: number; withTax: number };
deliveryEstimations?: { deliveryDateTime: { iso8601: string }; deliveryDays: { maximum: number; minimum: number } };
requiresDateSchedule?: boolean;
requiresTimeSchedule?: boolean;
}>;
homeDelivery?: Array<{
carrierGroupKey: string;
carrierKey: string;
deliveryOptionKey: string;
shippingOptionKey: string;
hideDivergingBillingAddress?: boolean;
imageFileName?: string;
collectionPointType?: string;
isDisabled?: boolean;
returnCosts?: { minBruttoOrderValueAfterReturns: number; returnServiceCost: number };
deliveryDate?: string;
deliveryDates?: { maximum: string; minimum: string };
serviceCosts?: { taxAmount: number; taxRate: number; withoutTax: number; withTax: number };
deliveryEstimations?: { deliveryDateTime: { iso8601: string }; deliveryDays: { maximum: number; minimum: number } };
requiresDateSchedule?: boolean;
requiresTimeSchedule?: boolean;
}>;
onlineDelivery?: Array<{
carrierGroupKey: string;
carrierKey: string;
deliveryOptionKey: string;
shippingOptionKey: string;
hideDivergingBillingAddress?: boolean;
imageFileName?: string;
collectionPointType?: string;
isDisabled?: boolean;
returnCosts?: { minBruttoOrderValueAfterReturns: number; returnServiceCost: number };
deliveryDate?: string;
deliveryDates?: { maximum: string; minimum: string };
serviceCosts?: { taxAmount: number; taxRate: number; withoutTax: number; withTax: number };
deliveryEstimations?: { deliveryDateTime: { iso8601: string }; deliveryDays: { maximum: number; minimum: number } };
requiresDateSchedule?: boolean;
requiresTimeSchedule?: boolean;
}>;
};
};
orderState: {
id?: number;
addresses?: {
billing?: {
street: string;
houseNumber?: string;
zipCode?: string;
city: string;
state?: string;
country: { iso2Code: string };
title?: string;
salutationCode?: 'f' | 'm' | 'd' | 'n';
firstName: string;
lastName: string;
additional?: string;
phone?: string;
forwardToCollectionPoint?: boolean;
isOriginal: boolean;
signature: string;
};
shipping?: {
street: string;
houseNumber?: string;
zipCode?: string;
city: string;
state?: string;
country: { iso2Code: string };
title?: string;
salutationCode?: 'f' | 'm' | 'd' | 'n';
firstName: string;
lastName: string;
additional?: string;
phone?: string;
forwardToCollectionPoint?: boolean;
isOriginal: boolean;
signature: string;
};
};
basket: {
packages: Array<{
id: string;
carrierGroupKey: string;
carriers: string[];
deliveryDate: { min: string; max: string };
isAvailable: boolean;
items: Array<{
id: string;
brand: { id: number; name: string };
colors?: Array<{ id: number; name: string }>;
displayData: {
identifier: { label: { translationKey: string }; value: string };
meta: { label: { translationKey: string }; value: string };
name: { label: { translationKey: string }; value: string };
};
discount: { sale: number; total: number };
imageUrl: string;
name: string;
merchant: { id: number; variantId: string };
pdpUrl: string;
productId: number;
quantity: number;
size: { shop: string; vendor: string };
styleKey: string;
unit: { costWithTaxWithoutVoucher: number; costWithoutTaxWithoutVoucher: number; taxWithoutVoucher: number };
variantId: number;
voucherId: string;
total: { costWithTaxWithoutDiscount: number; costWithTaxWithDiscount: number; costWithoutTaxWithDiscount: number };
}>;
}>;
tax: { amount: number };
id: string;
total: {
costWithTaxWithoutVouchersWithoutServiceCosts: number;
costWithTaxWithVouchersWithServiceCosts: number;
costWithTaxWithoutPromotion: number;
};
};
memberships?: { activated?: Array<{
membershipAccountNumber: string;
totalPointBalance: number;
redeemablePointBalance: number;
redeemablePointBalanceInCurrency: number;
redeemedPoints?: number;
redeemedPointsInCurrency?: number;
remainingPointBalance?: number;
}>; suggestions: Array<{ membershipTypeKey: string; earnings: { points: number } }> };
payment?: { giftCards?: Array<{
recurringPaymentOptionId: string;
recurringPaymentInformation: { giftCardCode: string; remainingAmount: number };
}>; selected?: Array<{
paymentOptionKey: string;
paymentOptionProvider: string;
isDisabled: boolean;
configuration?: {
initializationData?: any;
isRecurring?: boolean;
isAutoCapture?: boolean;
deferral?: { autoApplyDeferral: boolean; isSelected: boolean; isSupported: boolean; weeks: number };
fee?: number;
codPaymentFee?: number;
instalments?: Array<{ number: number; isSelected: boolean }>;
public?: { requiresTranslation?: boolean; requiresBrands?: string[] };
};
}> };
shipping?: { logisticsContact?: { plainText: string }; selected?: Array<{
carrierGroupKey: string;
carrierKey: string;
deliveryOptionKey: string;
shippingOptionKey: string;
hideDivergingBillingAddress?: boolean;
imageFileName?: string;
collectionPointType?: string;
isDisabled?: boolean;
returnCosts?: { minBruttoOrderValueAfterReturns: number; returnServiceCost: number };
deliveryDate?: string;
deliveryDates?: { maximum: string; minimum: string };
serviceCosts?: { taxAmount: number; taxRate: number; withoutTax: number; withTax: number };
deliveryEstimations?: { deliveryDateTime: { iso8601: string }; deliveryDays: { maximum: number; minimum: number } };
requiresDateSchedule?: boolean;
requiresTimeSchedule?: boolean;
}> };
vouchers?: Array<{ discount: number; id: string; isAppliedAutomatically: boolean; name: string; type: string; value: number; code: string }>;
promotions?: Array<{ id: string; code?: string; name?: string; discount: number; version: string }>;
promotionDiscounts?: Array<{ id: string; name?: string; discount: number }>;
promotionDiscountTotalAbsolute?: number;
taxId?: string;
};
notifications?: Array<{ id?: string; type: 'success' | 'info' | 'warning' | 'error'; text?: string; textTranslationKey?: string; replacements?: any }>;
};
AddressSuggestion
{
country: { iso2Code: string };
title?: string;
salutationCode?: 'f' | 'm' | 'd' | 'n';
firstName: string;
lastName: string;
additional?: string;
phone?: string;
forwardToCollectionPoint?: boolean;
isOriginal: boolean;
signature: string;
}
GiftCard
{
paymentOptionKey: string;
paymentOptionProvider: string;
isDisabled: boolean;
configuration?: {
initializationData?: any;
isRecurring?: boolean;
isAutoCapture?: boolean;
deferral?: { autoApplyDeferral: boolean; isSelected: boolean; isSupported: boolean; weeks: number };
fee?: number;
codPaymentFee?: number;
instalments?: { number: number; isSelected: boolean }[];
public?: { requiresTranslation?: boolean; requiresBrands?: string[] };
};
instalment?: { firstInstalmentValue: number; numberOfInstalments: number; subsequentInstalmentValue: number };
notifications?: Notification[];
serviceCosts?: { total: number };
recurringPaymentInformation: {
giftCardCode: string;
remainingAmount: number;
creditcardBrand?: string;
maskedCreditcardNumber?: string;
customerEmail?: string;
};
ConfirmOrderResponse
{
hasRedirect: boolean;
hasNotification: boolean
}
Examples
Show all available slot names on the page
(function() {
const scayleCheckout = document.querySelector("scayle-checkout");
if (!scayleCheckout) {
console.warn("Component 'scayle-checkout' not found.");
return;
}
const slots = scayleCheckout.shadowRoot.querySelectorAll("slot");
slots.forEach((slot) => {
const slotName = slot.name || "default";
const div = document.createElement("div");
div.innerHTML = `<strong>Slot Name:</strong><br/>${slotName}`;
div.style.border = "2px solid black";
div.style.padding = "12px";
div.style.width = "100%";
slot.appendChild(div);
});
})();
Injecting static HTML into the top of the basket
<script>
document.addEventListener('DOMContentLoaded', () => {
const replacementComponent = document.createElement('div');
replacementComponent.innerHTML = '<p>Injected HTML content</p>'
replacementComponent.slot = 'slot_basket_top';
const checkoutWebComponent = document.getElementsByTagName('scayle-checkout')[0];
checkoutWebComponent.appendChild(replacementComponent);
});
</script>
Injected a web component within a slot element
Please contact your SCAYLE Key Account Manager for access to internally developed add-ons such as Ingrid.
<script type="module" crossorigin src="./node_modules/scayle-ingrid/dist/scayle-ingrid.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const checkoutWebComponent = document.querySelector('scayle-checkout');
const ingridWebComponent = document.createElement('scayle-ingrid');
ingridWebComponent.slot = 'slot_replace_delivery_options';
checkoutWebComponent.appendChild(ingridWebComponent);
});
</script>
Mutating the state
Native checkout functions are exposed via the window object and can be interacted with from the storefront. Above you find the entire list of exposed checkout mutations.
window.scayleCheckoutFunctions.mutations.addVoucher({code: 'TEST123'});
The above snippet of code will execute the addVoucher
method with a code of "TEST123"
Listening for a change in the order state
window.scayleCheckoutEvents.addEventListener(
"state:updated",
({ detail: { state } }) => {
console.log('Checkout state updated:', state);
}
);
Sorting Payment Options
window.scayleCheckoutFunctions.sortPaymentOptions = (paymentOptions => {
return {
...paymentOptions,
generic: paymentOptions.generic.sort((a, b) => b.paymentOptionProvider.localeCompare(a.paymentOptionProvider)),
};
});
Filtering Payment Options
window.scayleCheckoutFunctions.filterPaymentOptions = ((paymentOptions) => {
return {
...paymentOptions,
generic: paymentOptions.generic.filter(({ paymentOptionKey }) => paymentOptionKey === "paypal_instant" )
}
})
The above filtering and sorting works after the next /state
update call. When the checkout mounts, we automatically make this call which would filter the payment options and apply the filters on every subsequent /state
update.
If it is needed to manually get the latest state immediately, this can be done by calling window.scayleCheckoutFunctions.mutations.getState()