2.0 Beta

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

What changed

Filters, sorting and pagination

Search & discovery lists products live from Shopify, with the filters of Shopify's Search & Discovery app, sorting and pagination designed in Webflow. Covers the block, every filter type, sorting, the count and active filters, pagination with page numbers and links that keep the filters.

v2.0 betaAdd-on: Search & discovery
Open .md1.x page ↗
On this page
  1. How it fits together
  2. 1. Add the block and the card
  3. 2. Add the filters
  4. Swatches
  5. Price
  6. Collection
  7. Text search
  8. Search inside a collection
  9. 3. Sorting
  10. Sort labels
  11. 4. Count, active filters and reset
  12. 5. Pagination
  13. Page numbers
  14. 6. Links, mobile panels and an apply button
  15. Other settings
  16. Before you publish
  17. Coming from 1.x

Search & discovery lists products straight from Shopify and lets the visitor filter, sort and page through them. The filters are the ones you set up in Shopify’s Search & Discovery app, such as colour, size, availability or price. You design each filter, the sort menu, the product card and the pagination in Webflow, and Smootify fills them.

Note

Before you start:

  • install Shopify’s free Search & Discovery app and create your filters in it (Filters, then Add filter). Note the label of each filter: you will type it in Webflow;
  • turn on the Search & discovery add-on in the Smootify dashboard. The Lite and Server plans include it. On your .webflow.io address it works without it, so you can build and test first.

How it fits together

What Smootify needs:

  • a smootify-search-discovery element;
  • inside it, one product card: a smootify-product element. Smootify repeats it once per product. Without a card, the block is removed.

What is up to you:

  • the layout: where the filters, the sort menu, the count and the pagination sit, and how they look;
  • which filters you show, and with which kind of element: checkboxes, a dropdown, swatches…;
  • whether the filters sit inside the block or in a panel elsewhere on the page.
Example structure of the Navigator
smootify-search-discoveryCustom Elementlimit=24
Text Block“0”filter=count
Div Block
smootify-productCustom Elementdata-id=filter
Text Link“Product name”product=url
smootify-priceCustom Element
Text Block“$0.00”data-prop=price

1. Add the block and the card

  1. Add a Custom element with the tag smootify-search-discovery.
  2. Inside it, add a Div block for the grid, and inside that a smootify-product with data-id="filter". Design it as a product card.

The first smootify-product is the template: each product of the results gets a copy of it. So every element of the card needs a Smootify attribute, such as product="title" or variant="image". Text bound only to a CMS field would show the first product’s text on every card.

A Collection list inside. You can use a Collection list of product cards as the grid. Its first Collection item becomes the template, and the other items stay on the page until the first results replace them. Search engines then see real products, and the page keeps its height while it loads. The cards can keep data-id bound to the Shopify ID field, or use data-id="loader": Smootify sets them to filter when the page loads. See placeholder cards.

Which products. Without other settings, the block lists the whole catalog. Three attributes narrow it, and the visitor cannot remove them, not even with the reset:

  • data-collection with the collection’s Shopify ID: the products of one collection. Use it on the collection page.
  • data-vendor with the vendor’s name, as written in Shopify: the products of one vendor. Use it on the vendor page. It needs the Vendor filter turned on in Shopify’s Search & Discovery app, as data-tag needs the Tag filter.
  • data-tag with a product tag, such as data-tag="summer": the products with that tag. Next to data-collection it works differently: see Search inside a collection.

How many per page. limit sets the number of products per page: 50 by default, 250 at most. Each card is a full product, so a lower number, such as 24, keeps the page fast, especially on phones.

When a filter picks an option value, such as Colour: Red, each card shows its variant with that value, with its image and price.

2. Add the filters

Each filter element shows one filter of Shopify’s Search & Discovery app. Put it inside smootify-search-discovery and give it the custom attribute label with the filter’s label, written exactly as in the app. Pick the element by how the filter should look:

filter-checkbox

Checkboxes

Built with
A Form Block with one Checkbox.
Label
label="Color"
Picks
Several values.
filter-list

Radio buttons

Built with
A Form Block with one Radio button.
Label
label="Size"
Picks
One value.
filter-select

The browser's own select

Built with
A Form Block with a Select field.
Label
label="Material"
Picks
One value.
filter-dropdown

A Webflow Dropdown

Built with
A Form Block and a Webflow Dropdown.
Label
label="Material"
Picks
One value.
filter-popover

A panel over the page

Built with
A Form Block and a popover with links or buttons.
Label
label="Material"
Picks
One value.
filter-swatches

Color or image buttons

Built with
A Form Block and one Custom element with the tag button.
Label
label="Color"
Picks
One value, or several with multiple="true".
filter-price

A price range

Built with
A Form Block with two number fields and two sliders.
Label
None: it reads no label.
Picks
A price range.
filter-search

A search field

Built with
A Form Block with a Text field.
Label
None: it reads no label.
Picks
Words to search.

Without its Form Block, or without a label where it needs one, the element is removed.

Example structure of the Navigator
filter-checkboxCustom Elementlabel=Colorshow-count
Text Block“Colour”
Form Block
Form
Field Label
Checkbox
Text Span“Value”class=w-form-label

Design one value only. The first Checkbox, Radio button, Dropdown link or button is the template, and Smootify copies it for every value of the filter. In a Select field, the first option stays as the placeholder, and Smootify writes the values after it.

Choices apply at once. A change reloads the products. For a panel that applies on a click, see the apply button in step 6.

Attributes on each filter element:

  • show-count adds the number of products next to each value, such as “Red (12)”; add hide-parenthesis for “Red 12”. A value with no products gets the class empty-count.
  • selected-value="Red" selects that value when the page opens. On filter-checkbox, list several with commas. The visitor cannot remove a preselected value unless you add allow-reset="true".
  • custom-label="Colour" changes the name shown in the active filters (see step 4).

A filter whose values are all gone hides itself. On smootify-search-discovery, hide-empty also hides the values with no products, and hide-if-single hides a filter that has only one value.

What the app decides. Each filter’s settings in Shopify’s Search & Discovery app apply on the site too. Values you group in the app show as one value, and the values keep the order you set there: Smootify does not sort them again. The behaviour you choose for a filter, such as whether two values combine with AND or OR, is applied by Shopify to the results. Give each filter of the app one element: to show the filters in a mobile panel, move them there with data-expand (step 6) rather than making a second copy.

Languages. Shopify translates the filter values, with these rules of its own:

  • the values of the Vendor and Tag filters are never translated: vendors always show in the store’s default language;
  • the Tag filter shows only to visitors browsing in the store’s default language;
  • translations follow the languages published in Shopify, not your markets.

Swatches

Inside the template button of filter-swatches, swatch="bg-color" paints the value’s colour as a background, swatch="color" as the text colour, swatch="image" shows its image, and swatch="title" its name. The colour or image is the value’s swatch in Shopify’s filter: see Swatch colours and images. The chosen button gets the class is-active. More in filter swatch parts.

filter-swatches keeps only its first button. Put any other button, such as an apply button, outside it.

Price

filter-price is always the price filter, so it needs no label. Inside it:

  • a Form Block with two Text fields of Type Number, for the minimum and the maximum, and two range sliders. Webflow’s form fields have no range type: add the two sliders with a Code Embed inside the form;
  • an element with filter-price="progress": the bar between the two handles;
  • optionally, filter-price="from-label" and filter-price="to-label" on text, for the selected minimum and maximum.
Example structure of the Navigator
filter-priceCustom Element
Form Block
Form
Text FieldType “Number”
Text FieldType “Number”
Text FieldType “Range”
Text FieldType “Range”
Div Block
Div Blockfilter-price=progress
Div Block
Text Span“$0”filter-price=from-label
Text“–”
Text Span“$100”filter-price=to-label

It needs exactly two number fields and two sliders: see price filter parts. The range starts from the prices of the first results. Shopify shows the price filter only in the shop’s default currency.

Style the sliders in the Code Embed. Smootify adds no style to them: write their CSS in the same Code Embed, for example the size and colour of the handles. Smootify places filter-price="progress" with its left and right edges, as a percentage of the track, so give it an absolute position inside a parent with a relative position.

Collection

label="Collection" makes a filter of all your collections. It works with the single-choice elements (filter-list, filter-select, filter-dropdown, filter-popover, filter-swatches), not with filter-checkbox. While a collection is chosen, the text search looks inside it: see Search inside a collection.

filter-search holds a Form Block with a Text field. Typing searches after a short pause. If the form has a submit button, the search runs on submit instead. It reads no label.

Search inside a collection

The text search also works on a collection: with data-collection, or while the visitor has chosen a collection in a Collection filter. Shopify has no search inside a collection, so Smootify compares two lists and shows the products in both:

  • the results of the search, up to 1,000, Shopify’s limit;
  • the products of the collection, up to 2,000. In a bigger collection, only the first 2,000 are compared.

What changes compared with a plain search:

  • Order. Relevance and price follow the order of the search. Best selling, title and date follow the order of the collection.
  • Filters. Their values and counts come from the search, so they count the whole catalog, not only the collection.
  • Pages. Previous and next, and the page numbers, work as usual.

For an exact search, use a tag. On a large or important collection, give its products a tag in Shopify, such as summer, and add data-tag="summer" to the block next to data-collection:

  • without a search, the block still shows the collection, in its order;
  • with a search, Smootify searches only the products with that tag. The results are exact, and the filters count only those products.

data-tag also works without data-collection: the block then always lists the products with that tag.

Warning

data-tag needs the Tag filter turned on in Shopify’s Search & Discovery app. Without it, Shopify ignores the tag without an error, and the tag narrows nothing. The debugger tells you when this happens.

3. Sorting

A sort element goes inside smootify-search-discovery, like a filter, with a Form Block inside it. There are four:

sort-select

The browser's own select

Built with
A Form Block with a Select field.
Good to know
The first option stays as the placeholder.
sort-radio

Radio buttons

Built with
A Form Block with one Radio button.
Good to know
The Radio button is the template of every option.
sort-dropdown

A Webflow Dropdown

Built with
A Form Block and a Webflow Dropdown.
Good to know
The toggle shows the current sort.
sort-popover

A panel over the page

Built with
A Form Block and links or buttons in a popover.
Good to know
The trigger shows the current sort.

The options come from Shopify, and depend on the list:

  • the whole catalog: relevance, and price low to high and high to low;
  • one collection (data-collection, or a chosen Collection filter): also best selling, title A to Z and Z to A, and oldest and newest first.

selected-value on the sort element picks an option when the page opens, by its label, such as selected-value="Price (Low to High)". Without it the store’s own order stays, and the trigger keeps the text you wrote in Webflow, such as “Featured”, until the visitor picks an option: Shopify does not tell which order a collection uses. Next to the element that shows the chosen order, a label of yours such as “Sort:” stays as you wrote it: the trigger then reads “Sort: Price (Low to High)”.

Sort labels

Each option has an English label, and each list shows only some of them:

KeyLabelShown for
relevanceRelevanceevery list
price_ascPrice (Low to High)every list
price_descPrice (High to Low)every list
best_sellingBest Sellingone collection
title_ascTitle (A - Z)one collection
title_dscTitle (Z - A)one collection
created_ascOldest to newestone collection
created_dscNewest to oldestone collection

To change them, go to Site settings › Custom code and add this script to Head code. Write only the labels you change: the others keep their English text.

<script>
  window.SmootifySortLabels = {
    relevance: "Featured",
    price_asc: "Price, low to high",
    price_desc: "Price, high to low",
    best_selling: "Best sellers",
    title_asc: "Name, A to Z",
    title_dsc: "Name, Z to A",
    created_asc: "Oldest first",
    created_dsc: "Newest first",
  };
</script>

selected-value matches the label as shown: after a change, write the new label, such as selected-value="Price, low to high".

Several languages. With Webflow Localization, each locale sets the page language in <html lang>. Pick the labels from it, and keep the English ones for the other locales:

<script>
  window.SmootifySortLabels = {
    it: { relevance: "In evidenza", price_asc: "Prezzo crescente", price_desc: "Prezzo decrescente" },
    fr: { relevance: "Pertinence", price_asc: "Prix croissant", price_desc: "Prix décroissant" },
  }[document.documentElement.lang.slice(0, 2)] || {};
</script>

4. Count, active filters and reset

These elements go anywhere inside smootify-search-discovery. All are optional.

  • filter="count" on text shows the total number of results.
  • filter="active" is the template of one active filter: a Div block, a link or a Custom element with the tag button. Smootify makes one copy per active filter, and a click on a copy removes that filter. Inside it, filter="active-label" shows “Colour: Red”.
  • filter="active-count" shows how many filters the visitor can remove.
  • A reset button: a Custom element with the tag button and type="reset". It removes every filter the visitor can remove, and the search words. It is disabled and gets is-disabled when there is nothing to remove.
  • filter="empty-state" on a Div block shows only when no product matches.
Example structure of the Navigator
Div Block
Div Blockfilter=active
Text Block“Colour: Red”filter=active-label
buttonCustom Elementtype=reset
Text“Clear all”
Text Block“No products match these filters.”filter=empty-state

Filters the visitor cannot remove, such as a value preselected without allow-reset, come first among the active filters, with the class preselected-filter, and a click on them does nothing.

5. Pagination

Pagination buttons are Custom elements with the tag button inside smootify-search-discovery. Their data-action decides how the visitor moves through the results:

data-action="previous"data-action="next"

Previous and next

Shows
One page at a time.
Good to know
The best choice for large catalogs.
data-action="page"

Page numbers

Shows
One page at a time, with the numbers to jump to, between previous and next.
Good to know
On a collection, it needs the Availability filter (see Page numbers).
data-action="load"

Load more

Shows
The next page, added below the products shown, on a click.
Good to know
Every page adds cards, which slows phones down on large catalogs.
data-action="load-in-view"

Load as the visitor scrolls

Shows
The next page, added below when the button scrolls into view.
Good to know
Every page adds cards, which slows phones down on large catalogs.

A button is hidden and disabled when there is no such page. Use previous and next, or one of the two load buttons, not all of them. Buttons inside a product card, such as the previous and next of a booking calendar, are not pagination buttons.

When new results appear, the page scrolls to the block. disable-scroll on smootify-search-discovery turns this off, and disable-scroll-on-load-more turns it off for the load buttons only.

Page numbers

Next to previous and next, the block can show page numbers, such as 1 … 4 5 6 … 12:

Example structure of the Navigator
smootify-search-discoveryCustom Elementlimit=24page-range=1
Div Block
smootify-productCustom Elementdata-id=filter
Text Link“Product name”product=url
Div Block
buttonCustom Elementdata-action=previous
Text“Previous”
buttonCustom Elementdata-action=page
Text Span“1”filter=page-number
Text Block“…”filter=page-ellipsis
buttonCustom Elementdata-action=next
Text“Next”
Div Block
Text“Page”
Text Span“1”filter=page-current
Text“of”
Text Span“12”filter=page-total
  • One number button. A Custom element with the tag button and data-action="page" is the template of every number: Smootify copies it once per number shown. Inside it, filter="page-number" holds the number; without it, the number becomes the button’s text. The current page gets the class is-active and cannot be clicked: style it with a combo class.
  • The gap. filter="page-ellipsis" is the template of the gaps between numbers, such as …. It is optional. When the gap is a single page, that page’s number shows instead.
  • How many numbers. page-range on smootify-search-discovery sets how many pages show on each side of the current one, 1 by default. The first and the last page always show.
  • “Page 3 of 12”. filter="page-current" and filter="page-total" on text. The total stays empty until Smootify knows it.
  • The class has-page-numbers is on smootify-search-discovery while there is more than one page to number: use it to hide the number bar otherwise.
  • In the address. With sync-query-params, the address also gets the page from the second one on, such as ?page=3, and a link with ?page=3 opens that page.

Note

On a collection, page numbers need the Availability filter turned on in Shopify’s Search & Discovery app. Shopify does not give the number of products in a collection, so Smootify adds it up from that filter. Without it the numbers do not show (previous and next still work), filter="count" shows only the products of the page, and on .webflow.io the debugger says why. A search counts at most 1,000 results, a Shopify limit.

Opening a page far from the current one takes a moment longer: Shopify gives the pages one after the other, so Smootify first reads the pages before it, with small requests. The pages already seen, and the next and previous ones, open at once.

Filters in the address. With sync-query-params on smootify-search-discovery, the address follows the filters, such as ?Color=Red, so a filtered page can be shared. Locked filters stay out of it. Even without it, a link to the page with a filter’s label and a value, such as /shop?Color=Red, opens it with that filter on, as long as the page has a filter element with that label. ?q= followed by words opens it with that search.

Filters outside the block. Filters and sort elements can sit in a panel elsewhere on the page, such as a side panel on mobile. Give the panel an ID in its element settings, and add data-expand="#filters" (with that ID) to smootify-search-discovery.

Filters in a popover. With auto-close-details="true" on smootify-search-discovery, a popover of filters inside it closes once the results change. See Popovers.

An apply button. A Custom element with the tag button and type="submit", inside the block but outside the filters’ forms, changes how filters apply: a choice updates the filters only, and the products reload when the visitor clicks the button.

Other settings

On smootify-search-discovery:

  • animation (fade by default, slide, scale, fadeBlurred, slideBlurred or none), duration, easing and stagger set how new cards appear;
  • unavailable-products sets where products that cannot be bought go: LAST (the default), HIDE or SHOW. It does not apply inside a collection;
  • avoid-webflow-restart skips restarting Webflow interactions after each render.

Every attribute is in smootify-search-discovery and search & discovery attributes.

While it loads. Add skeleton to the filters, the count and the card elements that should shimmer until the first results. Smootify removes it when it writes them. See loading.

Before you publish

Shopify’s own limits apply: a collection with more than 5,000 products, or a search with more than 100,000 results, shows no filters, and a filter shows at most 100 values. When a filter has more, group similar values in the app: a group holds at most 200 values, and a store can have at most 1,000 groups.

Check these first

  • A filter never shows. Its label is not written exactly as in Shopify’s Search & Discovery app, or none of the listed products has a value for it.
  • A filter element disappears. It has no Form Block inside, or it sits outside smootify-search-discovery and outside the data-expand panel.
  • Every card shows the same name or image. Those elements are bound to CMS fields only. Add product="title", variant="image" and the other attributes.
  • Only three sort options. Best selling, title and date exist only inside a collection.
  • data-tag changes nothing. The Tag filter is off in Shopify’s Search & Discovery app. Turn it on.
  • data-vendor changes nothing. The Vendor filter is off in Shopify’s Search & Discovery app. Turn it on.
  • A search in a big collection misses products. Only the first 2,000 products of the collection are compared with the search. Give the collection’s products a tag and use data-tag.
  • The count shows only the products of the page, and no page numbers appear. On a collection, the total comes from the Availability filter. Turn it on in Shopify’s Search & Discovery app.
  • The page is slow on phones. Lower limit, and use previous and next instead of loading more.

Coming from 1.x

  • Nothing shimmers by default any more: add skeleton where you want it.
  • filter="count" is now the total number of results; 1.x showed the products of the page.
  • filter-search reads no label, and filter-price is always the price filter.
  • filter-swatches keeps its first button and removes the others, a submit button included.
  • The text search works on collection pages: 1.x hid filter-search there with the hide-search class, which 2.0 no longer sets. Remove a shared filter-search from the collection pages if they should not have one.

    ↑ ↓ to moveEnter to openEsc to close