Global site search

One search box across the whole site - every enabled collection and static pages - relevance-ranked. Previously this meant writing custom JavaScript against the search API; now it's attributes, like everything else.

Shared setup - the script tag, keys, and data binding - is in the getting started guide. For a search box over a single CMS list, see keyword search.

Minimal setup

Three things: a wrapper with a key, an input, and at least one template card. The truly minimal version is one div - the results container defaults to the wrapper itself, and only rendered cards are ever cleared from it, so the input and state elements can live right beside them:

<div data-slater-search-list="site">
  <input type="text" data-slater-search="site" placeholder="Search…" />
  <a data-slater-template data-slater-item-href>
    <h3 data-slater-bind-text="name"></h3>
    <p data-slater-bind-text="matchedContext"></p>
  </a>
</div>
AttributeOnValueRequired
data-slater-search-lista wrapper (plain div)the block's key - shares one namespace with list keys, don't reuse oneyes
data-slater-search<input>the keyyes
data-slater-templateone or more cards inside the results container(no value) = default cardyes - there is no .w-dyn-item to fall back to. Templates are removed from the DOM at load, so mark placeholder cards freely.

The usual controls work with the key: data-slater-load-more, data-slater-empty, data-slater-count, data-slater-clear, data-slater-for.

Optional attributes

On the wrapper (config equivalents: window.SlaterSearchConfig.search = { site: { initialLimit, loadMoreAmount, minLength, siteId, endpoint } } - attributes win, as everywhere):

AttributeValueDefault
data-slater-resultsthe key - an explicit items containerthe wrapper itself
data-slater-min-lengthinteger - min chars before searching2
data-slater-page-sizeinteger20
data-slater-load-more-amountintegerthe page size
data-slater-siteWebflow site id<html data-wf-site>

Elsewhere:

AttributeOnPurpose
data-slater-initialany element, value = the keyShown only while the block idles (query empty / below min length).

Behavior

  • The block idles until the visitor types at least min-length characters; while idle the data-slater-initial element is shown and nothing is fetched - the empty element, count and load-more button are hidden/cleared. Clearing the input returns to idle, and a late response from an aborted request never repopulates the list.
  • Empty vs idle: data-slater-initial and data-slater-empty never show together. Any real response - even zero results - ends the idle state; zero results shows the empty element. A failed request shows neither: nothing was learned about the data, so the block stays as it was. Author both state elements visible - the embed hides them via the inline style (see the note in the getting started guide).
  • Deep links: ?q=term or ?query=term in the page URL runs the search on load and pre-fills the input (q wins when both are present). ?query= is what Webflow's native search form submits — and what a typeahead navbar input sends on Enter — so a nav-bar <form action="/search"> just works as a site-wide search bar.
  • Queries are capped at 100 characters — longer input is truncated, not an error.
  • Each new query resets load-more pagination to the first page.
  • A search block has no server-rendered fallback: if the very first request fails, the container simply stays empty (the idle element remains).

What you can bind

Results are normalized to the same shape as list items - every CMS field works with data-slater-bind-* - plus three reserved fields:

FieldValue
urlA ready link: the page's published path, or /<collection-slug>/<slug> for a CMS item
collectionThe result's collection slug, or the literal page for a static page
matchedContextA text snippet around the match, for display
Link cards with data-slater-item-href (no value - it uses url) or data-slater-bind-href="url". Don't write data-slater-href="{url}" — patterns percent-encode their placeholders, which mangles the slashes.

Different cards per collection

Give data-slater-template a value to use a different card (and link pattern) per collection; the value page is reserved for static pages. The valueless template is the default for everything else:

<div data-slater-results="site">
  <a data-slater-template data-slater-item-href> …generic card… </a>
  <a data-slater-template="blog" data-slater-href="/blog/{slug}"> …blog card… </a>
  <a data-slater-template="page" data-slater-item-href> …page card… </a>
</div>

Limits

  • No filters, sorting, facets, or locale yet - results come relevance-ranked. data-slater-filter / data-slater-sort controls pointed at a search block are ignored with a console warning. Need a filterable cross-collection list? That's exactly what a multi-collection list is.
  • The ranked window is the top 1000 results; load-more stops there.
  • data-slater-expand does work here - it expands references across every collection in the results. See Fields from a linked collection.
  • data-slater-search-fields does not - a site-wide search spans collections that share no field schema. Setting it here logs a warning and is ignored; scope a per-collection list instead.

Future: data-slater-search-mode="ai" (wrapper) and data-slater-overview (element) are reserved for the AI-powered variant - don't use these attribute names for anything else.