AddToCartForm
The product page buy box: options, notes and files, live price, quantity and the Add to cart button, submitted through Salla's SDK.
import { AddToCartForm } from '@salla.sa/twilight-theme-engine/components/product';In plain words
This is the part of a product page where the shopper chooses and buys: size or color options, a quantity, a note, and the Add to cart button. Hand it a product and it draws every input that product needs.
When the shopper submits, the Salla SDK sends the request and shows the "added" message; when they change an option, the SDK works out the new price.
It is lazy: its code downloads only when it first renders, so wrap it in React's <Suspense>, which shows a fallback while that happens.
Signature
const AddToCartForm: React.LazyExoticComponent<(props: {
product: Product; // the product details, with options
stickyAddToCart?: boolean; // the button's sticky bar on small screens
giftingIntro?: string; // subtitle of the gifting widget
formStartSlot?: ReactNode; // before the options
formEndSlot?: ReactNode; // after notes and files, before the price
}) => JSX.Element>
// The props type is not exported: use React.ComponentProps<typeof AddToCartForm>.Try it live
Loading products…
import { Suspense } from 'react';
import { AddToCartForm } from '@salla.sa/twilight-theme-engine/components/product';
import type { Product } from '@salla.sa/twilight-theme-engine/types';
// `product` must be the details (product.queries.detail): list products carry no options.
export function BuyBox({ product }: { product: Product }) {
return (
<Suspense fallback={null}>
<AddToCartForm
product={product}
formStartSlot={<p className="text-sm">{'Ships in 2 days'}</p>}
/>
</Suspense>
);
}
Example
import { Suspense } from 'react';
import { AddToCartForm } from '@salla.sa/twilight-theme-engine/components/product';
import type { Product } from '@salla.sa/twilight-theme-engine/types';
export function BuyBox({ product, sticky }: { product: Product; sticky: boolean }) {
return (
<Suspense fallback={null}>
<AddToCartForm
product={product}
stickyAddToCart={sticky}
formStartSlot={<p className="text-sm">Ships in 2 days</p>}
/>
</Suspense>
);
}
How it behaves
Submitting calls
Salla.form.onSubmit('cart.addItem', event): the SDK reads the form'sid,quantity, options, notes and files. Any change callsSalla.product.getPrice(new FormData(form)), but only afterform.reportValidity()passes, which also shows the browser's messages for required options still empty.What renders depends on the product: options (
options), bundles (has_bundle_products), weight and size guide, note and file inputs (can_add_note,can_upload_file), a pre-order countdown (has_preorder_campaignwithpreorder), and gifting (giftable). The quantity input is hidden foris_hidden_quantityand bookings, and capped atmax_quantity.Prices are the product's own
sale_price,regular_price,starting_priceorpricefollowed byCurrencySymbol, notuseMoney().format: no thousands separator and no Arabic digits.The button label is
product.add_to_cart_label; when that is empty the Salla button uses its own.notify_availability(itschannels,subscribedandsubscribed_options) is passed on to the Salla button, which runs the notify-me flow for an unavailable product.The engine's product page renders it as
<AddToCartForm product={product} stickyAddToCart={theme.settings.sticky_add_to_cart} />, between theproduct:single.form.startand.endhook slots.
Gotchas
Give it the product details (
product.queries.detail(id)), not a list item: list answers carryhas_optionsbut nooptions, so the option inputs never appear.product.queries.detail(id)first answers with the product's list card when a list on the page already loaded it (placeholderData, withisPlaceholderData: true). That stand-in has nooptionseither, so wait forisPlaceholderDatato befalsebefore rendering the form, or the options appear a moment later (src/api/product.ts).Option inputs appear only after
Salla.onReady()resolves, and the form first callsSalla.config.set('page.id', product.id). Rendering it outside a product page (a quick view on a category page) changes the SDK's current page id to that product.React.lazyexport: without a<Suspense>of your own, the nearest one above it (often the route's pending UI) replaces its whole area while the code downloads.
Related
The information half of a product page: brand, name, rating, price, description, tags, share and wishlist, SKU and stock counters.
ProductGalleryA product page's image slider with thumbnails, an in-page zoom popup, video and 3D slides, replaceable through the registry.
useProductKeeps a live copy of a product that follows price and stock changes from Salla option pickers, and can reload its details.