Search & Filtering
Shopify provides two related but distinct systems for helping shoppers find products: full-page search, and filtering within a collection (narrowing by price, size, color, and similar facets). Both are built into the platform rather than requiring a separate search app for basic use.
The search template and object
A search results page uses templates/search.json, and the search object exposes the query and its matches:
<p>{{ search.results_count }} results for "{{ search.terms }}"</p>
{% for item in search.results %}
{% if item.object_type == 'product' %}
{% render 'product-card', product: item %}
{% endif %}
{% endfor %}
search.results can mix products, articles, and pages in one list — checking object_type is how a template tells them apart before deciding how to render each one.
Predictive search
Predictive search is the dropdown of live suggestions that appears while a shopper is still typing, well before they submit the search form. It works by calling a dedicated endpoint from JavaScript as the input changes, rather than waiting for a full page load:
const res = await fetch(`/search/suggest.json?q=${encodeURIComponent(query)}&resources[type]=product`);
const data = await res.json();
renderSuggestions(data.resources.results.products);
Filtering a collection
On a collection page, collection.filters describes every facet available for that collection — price range, product type, size, color, and any filterable metafields or variant options a merchant has enabled — along with which values are currently active:
{% for filter in collection.filters %}
<fieldset>
<legend>{{ filter.label }}</legend>
{% for value in filter.values %}
<label>
<input type="checkbox" name="{{ value.param_name }}" value="{{ value.value }}"
{% if value.active %}checked{% endif %}>
{{ value.label }} ({{ value.count }})
</label>
{% endfor %}
</fieldset>
{% endfor %}
Submitting these as query-string parameters re-requests the collection page with the filters applied server-side — Shopify handles the actual matching logic, the theme just needs to render the available options and reflect which ones are active.
The section-rendering API
Reloading the whole page every time a shopper toggles a filter feels sluggish. The section-rendering API lets a theme re-request just one section's HTML for a given URL and swap it into the page with JavaScript, keeping the rest of the page (header, footer) untouched:
const url = `${window.location.pathname}?section_id=product-grid&${params}`;
const html = await (await fetch(url)).text();
document.querySelector('#product-grid').innerHTML = html;