Build the product page
The Shopify product on the template page of your Products collection. Covers title, price, gallery, options, add to cart and stock, and says what Smootify needs and what is up to your design.
A product page in Webflow is the template page of your Products collection. Smootify loads the live product from Shopify into it: price, options, stock, images and the add-to-cart form. This guide goes through the page one part at a time. For each part it says what Smootify needs and what is up to your design.
Note
Before you start, Smootify must be installed on the site and your products synced to the Products collection, with the Shopify ID field filled in.
How it fits together
Everything Smootify fills goes inside one element, smootify-product. It holds one product, and the elements inside it read that product and no other.
What Smootify needs:
- a
smootify-productelement with the product’s id; - inside it, the add-to-cart form, if the page sells.
What is up to you:
- the layout, the sections, the order of the parts, the classes and the styles;
- which parts you use. A page can show a price without a gallery, or options without a quantity field.
The smallest page that sells looks like this in the Navigator:
A Custom element comes from the Add panel. You set its tag in the element settings, and its attributes under Custom attributes in the same panel.
1. Connect the page to the product
- On the template page, add a Custom element with the tag
smootify-product. It can wrap the whole page or only the product section. - Give it the custom attribute
data-id, and take its value from the Shopify ID field of the collection.
Everything else on this page goes inside that element.
- Shared links to a variant. A link to the page with
?variant=and a variant id opens that variant. An id that is not one of the product’s variants, such as an old link to a variant you deleted, is ignored: the page opens on the first available variant. As the visitor picks options, the address follows the variant, so the link can be shared. This only works for the page’s own product: asmootify-productinside a Collection list, or inside the cart, ignores it. - Products Shopify does not return. A product that is unpublished or not sold in the visitor’s market leaves the product block empty, marked with the class
w-dyn-bind-empty. Smootify does not redirect. - Other products on the page. The same element also loads related products, best sellers or a collection: see the
data-idvalues insmootify-product.
2. Title, description and product details
Add a custom attribute to a Webflow element to fill it with a value of the product. What you type in the Designer stays as a placeholder until the product loads.
| Attribute | Put it on | What it shows |
|---|---|---|
product="title" | a Heading or text | the title |
product="description" | a Rich text element | the description, with its formatting |
product="vendor" | text | the vendor (brand) |
product="type", product="category" | text | the product type, the category |
product="tags" | text | one copy per tag |
product="collections" | text or a link | one copy per collection |
variant="sku", variant="barcode", variant="weight" | text | values of the selected variant |
Tip
Also bind the element’s text to the CMS field, such as the Name field for the title. The published page then has the text before Smootify loads, which helps search engines and avoids a flash of placeholders. Smootify then writes the live value from Shopify over it.
The full lists are in the Reference: product values and variant values.
Metafields
metafield="material" shows the product metafield custom.material. Add namespace="…" when the namespace is not custom, and use variant-metafield for a variant’s metafield. Every metafield type renders, including lists, ratings, JSON and references to other products: see metafield types.
In Shopify, the metafield definition must have Storefront access turned on. Without it the value never reaches the page.
3. Price
Add a Custom element with the tag smootify-price. Inside it, the elements with data-prop get the amounts, in the store’s money format:
data-prop="price": the price of the selected variant;data-prop="compareAtPrice": the compare-at price, hidden when the variant is not on sale;data-prop="total": the price times the quantity in the form.
The price follows the variant, the quantity and the selling plan. Put it anywhere inside smootify-product. Inside a swatch button, it shows the price of that button’s value instead.
Attributes on smootify-price change what it shows:
no-quantity: the total ignores the quantity;data-ignore="subscription-swatches": the one-time price, whatever selling plan is chosen;data-remove="…": removes that text from the formatted price;data-replace="from|to": replaces one piece of text with another.
variant="discount-percentage" shows 0% on a product that is not on sale. Put it inside an element with condition="on-sale", as above, so the badge only shows during a sale.
condition="not-on-sale" is the opposite: shown while the chosen variant is at full price, for a “regular price” label or a price style without the sale colour.
variant="discounted-amount" shows how much the variant saves, such as “€8.00”. Like the percentage, it comes only from the compare-at price: discount codes and automatic discounts never change it. The cart shows those. It shows €0.00 at full price, so put it inside condition="on-sale" too.
Price per unit. For products sold by weight, volume or length, the European pricing rules ask for the price per unit next to the price. Add variant="unit-price" to a text element: it shows the selected variant’s unit price and its reference unit, such as €1.50/ 100 g. The unit is in a span with the class reference-unit, so you can style it apart. data-format="{{price}} per {{unit}}" writes it your way. The element stays empty when the variant has no unit price.
The unit price comes from Shopify. On the product, in the pricing of each variant, fill in the unit price measurement: the variant’s total amount (such as 500 g) and the base unit to price it by (such as 100 g). Shopify then works out the price per unit. Shopify offers this setting to stores in some countries only.
Where the price format comes from. Smootify writes every amount with the store’s money format: the HTML without currency field of Shopify’s currency formatting (Settings › General, then Change currency formatting). Smootify keeps the format in the visitor’s browser and refreshes it in the background, so after a change, check it in a private window. The useBrowserFormatter option formats prices for each market with the browser’s own rules instead.
A sale that shows in one country and not in another can be Shopify hiding converted compare-at prices from European countries: see Markets.
4. Gallery
Add a Div block with product="gallery" and put the parts you need inside it. Every part is optional.
gallery="slider"goes on a Webflow Slider. Smootify makes one slide per image, each a copy of the first slide. Put an Image in the first slide, or use the slide’s background. The other slides you design are removed.gallery="thumbnails"goes on the element that repeats once per image, such as a Link block with an Image inside. Design one, and Smootify repeats it. The current one gets the classis-active, and a click moves the slider.gallery="lightbox"goes on a Lightbox link that opens every image. The link keeps what you put in it, such as a zoom icon.gallery="lightboxes"goes on a Lightbox link that repeats once per image, with its picture.
In the image settings, bind the Image of the first slide and of the thumbnail to the Image field, and their Alt text to Image Alt. If your Products collection uses the Image URL field, where the image stays on Shopify, bind the image to that field instead, with the same Image Alt. The page then shows the featured image before Smootify loads, and Smootify replaces it with every image of the product.
Attributes on the product="gallery" element:
include-mediaadds videos, YouTube and Vimeo videos and 3D models. Without it, the gallery shows images only.only-variant-imagesshows only the images of the variant the visitor picks: only the red t-shirt when they pick Red. How Smootify knows which images are the red ones is just below.variant-images="alt", together withonly-variant-images, groups the images by their alt text instead. The tag after the last#names the variant:Oak chair #Oak,# Red / M. An image without a tag shows for every variant. The alt text is public, since screen readers and Google read it, so write it to make sense read aloud.
Which images belong to which variant. In Shopify, each variant can have one image of its own, chosen on the variant’s page. That image is where the variant’s group starts: the group takes it and the images after it, in their Shopify order, up to the next image chosen for another variant. Photos placed before the first of these images belong to no variant, so the gallery never shows them once a variant is picked. Pick a colour and switch between the two ways:
Example: a t-shirt in three colors
1 The product's images in Shopify, in their order
Cotton t-shirtFront # RedBack # RedFabric # RedFront # BlueBack # BlueFront # GreenBack # Green2 The visitor picks a colour
3 The gallery shows
To show a photo with every colour, such as the photo of the model, group the images by alt text (variant-images="alt"): an image without # in its alt text shows with every variant.
When the variant changes, the slider moves to its image. Clicking an image does not change the variant. More in gallery parts.
5. Options
A picker shows the values of one option, such as Colour or Size, and changes the variant. There are four, each built on a different Webflow element:
Buttons, one per value
- Built with
- A Custom element
- Inside
- One Custom element with the tag button: the template of every value.
A Webflow Dropdown
- Built with
- A Custom element around a Dropdown
- Inside
- One Dropdown link: the template of every value.
A panel that opens over the page
- Built with
- A Custom element with a popover inside
- Inside
- Links or buttons inside the popover element.
The browser's own select
- Built with
- A Custom element around a Select field
- Inside
- Only the Select field: Smootify writes its options.
A picker goes anywhere inside smootify-product, inside or outside the add-to-cart form. You can use more than one kind on the same page, such as swatches for Colour and a dropdown for Size.
Design three pickers. A Shopify product has up to three options, such as Colour, Size and Material, and one template page serves every product. So give the page three pickers, one per option: data-option="1", "2" and "3". A picker removes itself when the product does not have that option: a product with one option shows one picker, a product with three shows all three, a product without options shows none.
Which option. Use data-option="1" for the first option, 2 for the second, or data-option-name="Color,Colour" for the first of those names that the product has, written exactly as in Shopify. The name is useful when products name their options differently, or in more than one language. Without either attribute, the picker shows the first option.
Design only the first value. The first button, or the first link, is the template. Smootify copies it for every value and removes the others you designed, so every attribute goes on the first one.
Each group holds the option’s name (variant="option1-name"), the value picked (variant="option1-value") and the picker. The group’s Div block has has-option, so it goes away together with its picker when the product does not have that option. Here the count starts at 0: has-option="0" is the first option, "1" the second, "2" the third. has-option works inside the add-to-cart form.
Inside the value of swatches, dropdowns and popovers:
option="title": the value’s name;option="bg-color"oroption="color": the swatch colour, as a background or as the text colour;option="image": the swatch image;option="price-difference": how much more the value costs than the cheapest one, such as ”+ €180”. It is hidden on the cheapest value, anddata-format="+ {{price}}"changes the text.
Swatch colours and images come from Shopify: the option’s own swatches, or the option metaobject in the product metafield custom.options. A native select can only hold text. On variant-selector, data-format="{{value}} {{difference}}" on the Select field adds the difference to each option’s text.
The selected value gets the class is-active. A value that cannot be bought gets is-disabled but stays clickable, because a sold-out variant can still be chosen. Style both with combo classes.
Show the option and the chosen value. Inside the picker, selected-option="name" writes the option’s name and selected-option="title" the chosen value, for example in a label or a dropdown toggle that reads “Size: M”. The name comes from the picker’s data-option-name or data-option, so the label never needs to be typed again:
Anywhere else in smootify-product, use variant="option1-value" (or option2-value, option3-value) for the value and variant="option1-name" for the name, as in the groups above.
Two attributes on smootify-add-to-cart change how pickers behave. allow-unavailable lets the native select pick values that cannot be bought. avoid-option-update keeps the value picked in a dropdown or popover when the variant changes from another picker.
The page’s product loads all its variants, even above 250.
6. Add to cart
Add a Custom element with the tag smootify-add-to-cart and put a Webflow Form Block inside it. The form is required: without one, the element is removed.
The buttons. The add button can be either of the first two kinds. Buy now is optional, a second button next to it:
A Webflow Form Button
- For
- A button with text only.
- Loading
- Its Waiting text setting.
A Custom element with the tag button
- For
- An icon, two labels, anything inside.
- Loading
- Two elements inside:
data-state="default"anddata-state="loading".
A second button, for Buy now
- For
- Skipping the cart.
- Built with
- A Custom element with the tag button and
type="submit". Not a Webflow Button: that is a link.
Quantity. Add a Custom element with the tag quantity-input. Put a Text field named quantity inside it. The minus and plus buttons are optional: they are Custom elements with the tag button and data-action="minus" or data-action="plus". Without a quantity field, the product is added once. The minus button is disabled and gets is-disabled at the lowest quantity, and the plus button at the highest: the stock left, or the maximum of a B2B quantity rule. data-disable-max on quantity-input removes that upper limit.
Extra fields. Any other field in the form, such as a text field, a select or a checkbox, is saved on the cart line. Its field name is the label, and it shows at checkout: use it for an engraving or a gift message. A name that starts with _ is saved but hidden at checkout. A name that starts with ##ignore is not saved. Extra fields never change the price: for options that cost more, use add-ons or the product configurator.
When the variant cannot be bought. If the variant is sold out, or the picked combination does not exist, every submit button in the form is disabled and gets the class is-disabled. Shopify’s errors, such as a quantity above the stock, appear in the form’s Error message. The Success message is never shown: the form stays on screen, ready for the next product.
A button outside the form. A sticky bar with its own Add to cart button can sit anywhere on the page. Give the Form an ID in its settings, such as product-form, and make the button a Custom element with the tag button, the custom attribute type set to submit and form set to that ID. It adds to the cart, shows its loading label and is disabled with the others. The ID must be unique on the page, so use it on the product page, not in a list of cards.
7. Stock, sale and other states
An element with condition="…" inside smootify-product shows only while the product is in that state. The element stays on the page and Smootify shows or hides it. This is separate from Webflow’s conditional visibility. Each card shows a value of condition and the kind of message you would put in that element:
The selected variant can be bought.
The selected variant cannot be bought.
5 or fewer left (0 counts too).
2 to 5 left.
Exactly one left.
More than 5 left.
Out of stock but still sold.
A compare-at price above the price.
The picked combination does not exist.
Published less than 30 days ago (data-new-days changes it).
A selling plan is chosen.
No selling plan is chosen.
Every condition is in product conditions.
- Variants.
condition="is-variable"shows an element when the product has more than one variant, such as the options block, andis-not-variablewhen it has only one. - Subscriptions.
condition="subscription"follows the visitor’s choice: it shows while a selling plan is chosen insubscription-swatches, andno-subscriptionwhile the one-time purchase is. It does not tell whether the product offers subscriptions. - Tags.
tagged="gift,new"keeps an element only when the product has every one of those tags. Addany="true"to keep it when the product has at least one.not-taggeddoes the opposite: see tag conditions.
smootify-product also carries classes for the same states, such as is-available, is-on-sale, low-stock, is-variable and loaded. You can style them as combo classes: see state classes.
When the product is not available. Shopify does not return a product that is not published on the Headless channel, or not sold in the visitor’s market. The page’s smootify-product is then hidden, and the page gets the class product-unavailable. Two conditions work anywhere on the page, outside smootify-product too:
condition="product-unavailable"shows an element only in that case, such as a message with a country switcher;condition="product-available"does the opposite: it hides an element in that case.
When the visitor picks a country where the product is sold, the class goes away, the message hides and the product shows. Only the page’s own product counts: cards in Collection lists, cart lines and products inside other products are hidden as before, and do not turn the condition on.
While it loads. skeleton="text", "button", "block" or "image" shows a placeholder shimmer on an element until Smootify fills it, and skeleton="hide" hides it until then. Only elements that have the attribute shimmer. See loading.
8. Subscriptions
To sell by subscription, the store needs a Shopify subscription app that creates the selling plans. Smootify shows and sells them.
Put a Custom element with the tag subscription-swatches inside the form, with a Webflow Tabs element in it:
- the first tab is the one-time purchase, and is removed when the product can only be bought by subscription;
- the second tab is the template for each selling plan group. In its pane, a Radio button is the template for each plan;
subscription-group="name"shows the group’s name in the tab. Asmootify-priceinside a plan’s Radio button shows that plan’s price.
On a product without selling plans, subscription-swatches is removed. The attributes that preselect a plan are in subscription-swatches.
9. Search engines
Smootify adds the product’s structured data (JSON-LD) to the page, so Google can show the product as a rich result. It includes:
- the name, description, images and brand;
- for each variant, the price in the visitor’s currency and whether it is available;
- the rating, when the page shows the
reviews.ratingandreviews.rating_countmetafields (Google wants a marked-up rating to be visible on the page).
There is nothing to add. If the page already has its own Product structured data, Smootify leaves it alone. To turn it off, set structuredData: false in the Smootify options.
For Google Shopping, the product feed of Shopify’s Google & YouTube app is still the reference.
Before you publish
On your .webflow.io address, press Alt⇧ ShiftD (⌥ Option⇧ ShiftD on a Mac) to turn on Smootify’s debugger. On a phone, open the page with ?smootify-debug at the end of the address. Its button then shows on every page of the site, and its panel lists the elements that are out of place. The debugger explains the rest.
Check these first
- Nothing loads.
data-idis empty or not bound to the Shopify ID field. - Attributes on a swatch do nothing. They are on the second button: only the first one is the template.
- A picker disappears. The product does not have that option, or the picker is inside an element hidden by Webflow’s conditional visibility, which removes it.
- A metafield stays empty. Its definition in Shopify needs Storefront access.
- Videos are missing from the gallery. Add
include-mediato theproduct="gallery"element. - The gallery does not move.
gallery="slider"only works on a Webflow Slider. - Buy now does nothing. It is a Webflow Button, which is a link. Use a Custom element with the tag
button.