# Search results page

> A page that lists every product matching a search, from the words in its address or typed in its field, with a count, pagination and an empty state. Covers smootify-search-page and how visitors reach it.

Status: Ready (Smootify 2.0)  
Add-on: Search  
URL: https://www.smootify.io/docs/astro/build/search-page  
Updated: 2026-10-21

The search results page lists every product that matches a search, page by page. The words come from the page address (`?q=` followed by the words) or from a field on the page. Unlike [predictive search](https://www.smootify.io/docs/astro/build/predictive-search), it has no limit of 10 results.

> [!NOTE]
> Turn on the **Search** add-on in the Smootify dashboard. The Lite and Server plans include it. On localhost and on your `*.workers.dev` address it works without it, so you can build and test first.

## How it fits together

What Smootify needs:

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

What is up to you:

- the page layout and the card design;
- the optional parts: a search field, the count, the searched words, the empty state, the pagination.

```html
<smootify-search-page limit="24">
  <form><input type="search" name="q"></form>
  <div><span search="count">0</span> results for <span search="query">shoes</span></div>
  <div>
    <div class="sm-dyn-item">
      <smootify-product data-id="search">
        <a product="url" href="#">Product name</a>
        <smootify-price><div data-prop="price">$0.00</div></smootify-price>
      </smootify-product>
    </div>
  </div>
  <div search="empty-state">No products match your search.</div>
  <button type="button" data-action="load">Load more</button>
</smootify-search-page>
```

## 1. Create the page

1. Create a page, such as `src/pages/search.astro`, and give it `<Seo type="other" title="Search" />`: see [Content from Shopify](https://www.smootify.io/docs/astro/start/content#5-seo-helpers).
2. Add a [`smootify-search-page`](https://www.smootify.io/docs/astro/reference/elements/smootify-search-page) element. It can wrap the whole page or only the results section.

Visitors reach the page in three ways:

- from predictive search, with a link that has `search="search-page"`: see [Predictive search](https://www.smootify.io/docs/astro/build/predictive-search);
- from any link to the page with `?q=` and the words, such as `/search/?q=linen+shirt`;
- by typing in the page’s own field.

The address follows the search, so a results page can be shared.

## 2. The search field

Add a `<form>` inside `smootify-search-page`, with an `<input type="text">` or an `<input type="search">`. Its `name` does not matter: Smootify renames it and fills it with the words from the address. Typing searches after a short pause, and Enter searches at once.

The field is optional: without it, the page shows the results for the words in the address.

The page can have more than one field, such as a form at the top and another above the results: each one searches the words typed in it. A field inside a result card does not start a search.

## 3. The results

Add a `smootify-product` with `data-id="search"` and design it as a [product card](https://www.smootify.io/docs/astro/build/product-cards). The first `smootify-product` is the template: each result gets a copy of it, so give each element of the card a Smootify attribute, such as `product="title"`.

Wrap the card in an element with the class `sm-dyn-item`, the boundary of the card. No placeholder card is needed: Smootify clones the first `smootify-product` of the block, and the first results replace the list in one step.

Attributes on `smootify-search-page`:

- `limit`: products per page, 50 by default, 250 at most;
- `animation`, `duration`, `easing` and `stagger`, and `disable-scroll`, as on search & discovery: see [Filters, sorting and pagination](https://www.smootify.io/docs/astro/build/filters).

**Products that cannot be bought.** `unavailable-products` on `smootify-search-page` says where they go. Here results 3 and 5 are sold out:

| `unavailable-products` | Products that cannot be bought |
|---|---|
| `LAST` (default) | come after the others |
| `HIDE` | are left out |
| `SHOW` | keep their place in the results |

The search covers products only.

## 4. Count, words, empty state and reset

Before a search and after it, the page shows different parts: an element with `search="no-query"` shows only while there is no query, such as “What are you looking for?” with a few suggested searches; one with `search="with-query"` shows only once there is one, such as the “Results for … · 12 pieces” line; `search="empty-state"` shows only when a search finds nothing. `smootify-search-page` also gets the class `has-query` while there is a query and `is-empty` when it finds nothing, and the stylesheet shows and hides these parts from those classes: do not write `hidden` on them. All optional, anywhere inside `smootify-search-page`: `search="count"` and `search="query"` on text, `search="empty-state"` on any element. What they show for three searches:

| Search | `search="count"` (on text) | `search="query"` (on text) | `search="empty-state"` (on any element) |
|---|---|---|---|
| `?q=linen`, 12 results | 12, the number of results | linen, the searched words | hidden |
| `?q=xyzzy`, no results | 0 | xyzzy | shown |
| no words in the address or the field | | | shown: the page searches nothing |

A reset button, a `<button type="reset">`, clears the search.

Every attribute is in [search page attributes](https://www.smootify.io/docs/astro/reference/attributes/search-page).

## 5. Pagination

The pagination buttons work as on search & discovery. Each is a `<button type="button">` with one of these `data-action` values:

| Buttons | Shows |
|---|---|
| `data-action="previous"` and `data-action="next"` | one page at a time |
| `data-action="page"` | one page at a time, with numbers to jump to, such as 1 … 4 5 6 … 12 |
| `data-action="load"` | adds the next page below the products shown, on a click |
| `data-action="load-in-view"` | adds the next page below when the button scrolls into view |

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

Page numbers work as on search & discovery too: one `button` with `data-action="page"` as the template of the numbers, `filter="page-ellipsis"` for the gaps, `filter="page-current"` and `filter="page-total"` for “Page 3 of 12”, and `page-range` on `smootify-search-page`. See [Page numbers](https://www.smootify.io/docs/astro/build/filters#page-numbers). The address always follows the page, such as `?page=3`. A search counts at most 1,000 results, a Shopify limit.

## A search page with filters

`smootify-search-page` has no filters. For search results with filters and sorting, use [search & discovery](https://www.smootify.io/docs/astro/build/filters) on the page instead, with a `filter-search` field. It reads the same `?q=` from the address, so the links from predictive search keep working. It needs the Search & discovery add-on, and without words it lists the whole catalog.

## Before you publish

> [!STUCK]
> - **The block disappears.** It has no `smootify-product` card inside.
> - **The page opens empty.** The address has no `?q=`. A form that sends its words under another name, such as `?query=`, is not read: the page reads `?q=`.
> - **Typing in the field does nothing.** Only an `<input type="text">` or an `<input type="search">` is read; an email or number input is not.
> - **Every card shows the same name.** Those elements have no Smootify attribute, so the first card's text is copied. Add `product="title"` and the other attributes.
> - **Sold-out products are always at the end.** That is the default. Set `unavailable-products="SHOW"` to keep them in their place.
