2.0 Beta

Smootify 2.0 is in public beta. Your 1.x store keeps working. Move when you want.

What changed

Magic Box

A box the customer fills with products you choose, under rules you set, that reaches the cart and checkout as one line with its own title, image and discount.

v2.0 betaAdd-on: Magic Box
Open .md
On this page
  1. How it fits together
  2. 1. Give the box a title, an image and a discount
  3. 2. Build the box
  4. 3. Set the size of the box
  5. 4. One product per category
  6. 5. Show progress and the price
  7. 6. In the cart and at checkout
  8. Before you publish

Magic Box lets the customer build a box: a case of 6 wines, a sampler of 3 coffees, a PC with one part from each category. The customer picks products from the lists you design, and the box goes to the cart as one line, with its own title and image. At checkout it stays one line, and it can carry a discount. This page covers the Shopify side, the box, its rules, categories and the box panel.

Note

Turn on Magic Box in the Smootify dashboard of the site. It is included in every plan, the free one too, but it always needs to be turned on. Turning it on adds the Magic Box metaobject definition to Shopify and the checkout function that merges the box into one line.

How it fits together

Everything goes inside one element, smootify-magic-box.

What Smootify needs:

  • a smootify-magic-box element;
  • inside it, the products the customer can pick, each with its own add-to-cart form. Inside the box, these forms add to the box instead of the cart;
  • inside it, a smootify-magic-box-cart: the box panel. It holds a box-item template, repeated once per product in the box, and a <form> that adds the whole box to the cart. Without it, the box is removed.

What is up to you:

  • how the products are listed: a loop over entries, several lists, a slider;
  • where the box panel sits (a sidebar, a sticky bar, under the products) and what it shows;
  • the layout, classes and styles of every part.

A fixed box of 6 looks like this:

<smootify-magic-box data-min="6" data-max="6">
  <div class="sm-dyn-item">
    <smootify-product data-id="1234567890">
      <div product="title">Name</div>
      <smootify-add-to-cart>
        <form><input type="submit" value="Add to box"></form>
        <div form-fail hidden>Something went wrong</div>
      </smootify-add-to-cart>
    </smootify-product>
  </div>
  <smootify-magic-box-cart>
    <items-list>
      <box-item><div box-item="title">Product</div><div box-item="quantity">1</div><button type="button" data-action="remove">Remove</button></box-item>
    </items-list>
    <empty-state>Your box is empty</empty-state>
    <form><input type="submit" value="Add the box to cart"></form>
    <div form-done hidden>Added</div>
    <div form-fail hidden>Something went wrong</div>
  </smootify-magic-box-cart>
</smootify-magic-box>

Render one product card for each product of the list.

1. Give the box a title, an image and a discount

In the cart and at checkout, the box line shows a title and an image of its own. There are two ways to set them.

A Magic Box entry in Shopify. In Shopify, go to Content > Metaobjects > Magic Box and create an entry with a Title, an Image and, if you want one, a Discount Percentage. On smootify-magic-box, set data-handle to the entry’s handle. The merchant can then change the title, the image or the discount in Shopify without touching the site.

A static box. Set data-title and data-image on smootify-magic-box. The image must be a Shopify file: upload it in Shopify under Content > Files and copy its URL. Checkout ignores an image from anywhere else.

Warning

The discount can only come from a Magic Box entry. A static box has no discount.

The discount applies to every box the customer can add to the cart under its limits, not only to a full one. For a discount only on a full box, give the box the same data-min and data-max, such as data-min="12" data-max="12".

The discount is a percentage off the whole box, applied at checkout.

2. Build the box

  1. Write a smootify-magic-box element around the products and the box panel.
  2. Inside it, list the products. Any list works: cards rendered from your product entries (product cards), or a list loaded from Shopify (product lists). Each card needs a smootify-add-to-cart with a <form> inside. Its button adds the product to the box. Variant pickers and a quantity field work as on the product page.
  3. Inside smootify-magic-box, write a smootify-magic-box-cart element. Put inside it:
    • an items-list element, holding one box-item element. The box-item is the template: Smootify repeats it for each product in the box. items-list shows only while the box has products;
    • optionally, an empty-state element, shown only while the box is empty;
    • a <form> with a submit button. It adds the whole box to the cart.

Inside box-item:

  • box-item="title", box-item="image", box-item="price", box-item="total" (price × quantity), box-item="quantity" and box-item="category" show the product in the box;
  • the product and variant values also work, such as variant="title" for the variant name. See box item values;
  • a button with data-action="remove" takes the product out of the box.

After a product goes into the box, the quantity field of its form goes back to 1.

3. Set the size of the box

These attributes go on smootify-magic-box:

AttributeWhat it doesDefault
data-minthe fewest products the box can hold1
data-maxthe most products the box can hold100 (also the highest value)
data-stepthe box size must be a multiple of this1
data-uniquethe same product can go in only onceoff

The box can be bought when the number of products is between data-min and data-max and a multiple of data-step. The add button stays disabled until then. Some sizes and the boxes they allow:

data-min="6" data-max="6"

A fixed size

Can be bought
With exactly 6 products.
data-min="6" data-max="12" data-step="6"

Sizes you choose

Can be bought
With 6 or 12 products, nothing in between.
data-max="10"

A free mix with a limit

Can be bought
From 1 to 10 products: data-min is 1 unless you set it.
data-min="10" data-max="25" data-step="15"

Sizes that do not share the step

Can be bought
With 15 products only: 10 and 25 are not multiples of 15.
Instead
A box of 10 or 20 needs data-step="10".

Warning

Every size must be a multiple of the same step. A box of 1, 3 or 6 cannot be written with one step.

data-unique and the category rules below are on whenever they have a value, even false. Write true, and remove the attribute to turn a rule off.

When a product does not fit, the product’s form shows an error in its [form-fail] block. You can change the text of each error:

  • data-full-error: the box is full. Default “Box is full”;
  • data-too-many-error: the quantity is more than what fits. {quantity} in the text becomes the number that still fits;
  • data-only-one: the product is already in the box and data-unique is on. Default “You can add only 1 item inside the box”;
  • data-only-one-per-category: the category already has a product. {category} becomes the category name. Default “You can add only 1 item of {category} inside the box”.

4. One product per category

For a box that needs one piece from each group (a base, a sauce and a topping; a PC with a motherboard, a GPU and RAM), split the products into categories.

  1. Wrap each group of products in a smootify-box-category element.
  2. Give it the attribute data-name with the category name, such as Sauce.
<smootify-box-category data-name="Sauce">
  <div class="sm-dyn-item">
    <smootify-product data-id="1234567890">
      <div product="title">Name</div>
      <smootify-add-to-cart>
        <form><input type="submit" value="Add"></form>
        <div form-fail hidden>Something went wrong</div>
      </smootify-add-to-cart>
    </smootify-product>
  </div>
</smootify-box-category>

Render one such card for each product of the category.

Then choose the rules on smootify-magic-box. For a pizza with a Base, a Sauce and a Topping:

data-unique-per-category="true"

One product per category

A second pick
In the same category, it shows an error in the Error message of the product's form.
data-auto-remove-category="true"

A new pick replaces the old one

Works
Only with one product per category on.
A second pick
Takes the place of the first in its category, with no error. For a configurator.
data-all-categories="true"

Every category filled

Can be bought
Only when every category has a product.
Until then
The add button stays disabled.

Steps without interactions. Put each category in a slide of a slider ([slider-track], each slide one of its children), or in a panel of ARIA tabs ([role="tablist"] with its [role="tab"] buttons and [role="tabpanel"] panels): see Write components with Smootify elements. When the customer adds a product, the slider or the tabs move on: to the next empty category with data-all-categories, otherwise to the next slide or tab. When the customer removes a product, it goes back to that product’s category. Smootify runs the [slider-prev], [slider-next] and [slider-dots] placed inside the Magic Box.

Completed categories. A category gets the class is-complete while the box holds at least one of its products, and so do the slide and the [role="tab"] that show it when every category in them has one. To show a check mark inside a tab, put it in an element with box-condition="category-complete"; box-condition="category-incomplete" is the opposite. They work inside the category, its slide and its tab.

In the box panel, data-prop="missingCategories" lists the categories still empty, separated by commas. separator changes the separator, and separator="repeat" makes one copy of the element per missing category.

5. Show progress and the price

Inside smootify-magic-box-cart, outside the box-item, these elements follow the box:

<div><span data-prop="currentQuantity">0</span> / <span data-prop="maxQuantity">6</span></div>
<div><div data-prop="leftQuantityWidth"></div></div>
<div box-condition="cannot-purchase">Missing: <span data-prop="missingCategories">Base, Sauce</span></div>
<smootify-price>
  <div data-prop="price">$0.00</div>
  <div data-prop="compareAtPrice">$0.00</div>
</smootify-price>
<div box-condition="can-purchase">You save <span data-prop="discount-amount">$0.00</span></div>
  • data-prop="currentQuantity", "minQuantity", "maxQuantity", "leftQuantity" (how many more fit): numbers;
  • data-prop="leftQuantityWidth" on an element: its width follows how full the box is, for a progress bar. data-prop="leftQuantityPercentage" shows the same as text;
  • data-prop="discount-percentage" and data-prop="discount-amount": the discount of the box, as a percentage and as money;
  • a smootify-price shows the box total after the discount in data-prop="price", and the total before the discount in data-prop="compareAtPrice" when there is one;
  • box-condition="can-purchase" and box-condition="cannot-purchase" show an element only while the box can, or cannot yet, be bought.

smootify-magic-box-cart also gets classes you can style. For a box of 6 wines at $20.00 each, the panel goes through these states:

is-empty · is-disabled

Empty

Shows
empty-state instead of items-list, and box-condition="cannot-purchase".
Add button
Disabled.
is-disabled

Filling: 4 of 6

Shows
items-list and box-condition="cannot-purchase".
Add button
Disabled.
is-purchasable

Ready: 6 of 6

Shows
box-condition="can-purchase".
Add button
Enabled.
is-purchasable · is-saving

Ready, with a 10% discount

Discount
From the Magic Box entry. is-saving while it applies.
Price
data-prop="price" after the discount, data-prop="compareAtPrice" before it.

The full lists are in Magic Box values and Magic Box conditions.

The add button. A submit button works: an input or a <button type="submit">. It is disabled until the box can be bought. A second <button type="submit" name="buy-now"> adds the box and goes straight to checkout. data-buy-now="true" on smootify-magic-box-cart sends every submit to checkout.

Extra fields. A field in the box’s form, such as a gift message, is saved with the box, under its field name, and shows with the box in the cart. A name that starts with _ is saved but not shown.

6. In the cart and at checkout

The box is one line in the cart, with the box title and image. In the cart, a box-item inside the cart-item template repeats once per product in the box, with the cart line values such as box-item="title" and box-item="quantity". The customer cannot change the quantity of a box: its quantity field is removed. With a box-item in the template, cart-item="options" lists only the box’s own fields, such as a gift message. Without one, it lists the products as text (“1 x Wool Socks”).

At checkout Shopify shows the box as one line, with its title, image and discount.

Subscriptions. A box cannot be sold as a subscription: Shopify does not merge cart lines that have a selling plan. See subscriptions for what you can build instead.

Developers can add a box to the cart from code with addBoxToCart. They can also change the box title and image as the box fills, for example “Box of 4 wines”: see the Magic Box example.

Before you publish

On the dev server and on your *.workers.dev address, the Smootify debugger lists the Magic Box elements and tells you when they are not running. See the debugger.

Check these first

  • Products go straight to the cart, one at a time. Magic Box is not turned on in the Smootify dashboard. It needs to be on.
  • The whole box disappears. smootify-magic-box-cart is missing, or data-handle does not match the handle of a Magic Box entry in Shopify.
  • The add button never turns on. The number of products is not between data-min and data-max, or not a multiple of data-step, or a category is empty with data-all-categories.
  • There is no discount. The box is static (data-title, data-image). Only a Magic Box entry carries a discount.
  • The box image is missing at checkout. The data-image URL is not a Shopify file. Upload it under Content > Files.
  • A rule is on though you wrote false. These rules turn on with any value. Remove the attribute instead.

    ↑ ↓ to moveEnter to openEsc to close