Skip to content

    Pre-launch API. The concepts described here are settled, but the API shape is not: request and response fields, parameters and defaults can still change. Build against it, and talk to your Luigi's Box contact before you put an integration into production.

    Search results

    View source

    The search widget takes over your existing search results page. It renders into an element of your page, hides your own listing while its own is shown, and leaves the rest of the page — header, breadcrumbs, footer — as it is. Your search form keeps submitting to the same URL.

    integration/search/_config.ts:

    export default {
    urlMatch: '^/search$',
    queryParam: 'q',
    anchor: '#search-results',
    position: 'prepend',
    surface: 'lbs_search_main',
    size: 24,
    facets: ['brand', 'color', 'lbx:price'],
    sorts: ['', 'lbx:price:asc', 'lbx:price:desc'],
    fields: ['@title', 'url', 'image_url', 'price', 'brand'],
    quick: [{ type: 'category', size: 4 }],
    };
    KeyDefault
    urlMatchAny page with queryParamA regular expression on the URL’s path
    queryParam—The query parameter holding the search query. Without it, the first capture group of urlMatch is the query: ^/search/([^/]+)$.

    For URLs a regular expression cannot describe, set functions in search/_init.ts:

    Hook
    active(url)Whether this URL is a search page
    readQuery(url)The query on this URL

    A search page without a query is left to your site.

    KeyDefault
    quick—Other object types shown above the results, such as category or brand tiles. One request per entry: { "type", "size", "fields" }.
    inPlaceQuerytrueA new query from your search form while on the search page renders in place, with a new history entry and no page load. Set false when parts of your search page outside the listing are server-rendered and must follow the query, or when your page-view analytics must fire per search.
    prefetchWhileTypingtrueOnce the phrase typed in your search input settles, its results are fetched, so Enter shows them at once
    prefetchDelayMs300How long the phrase must stay unchanged first
    prefetchMaxAgeMs120000How long a result fetched while typing is used
    prerenderWhileTypingfalseIn Chrome and Edge, also prerender the search page of the settled phrase, so Enter from another page shows a page already rendered. Each settled phrase costs your server a page render, and your analytics count a page view unless they wait for the prerendered page to be shown.
    prerenderEagernessimmediateimmediate or eager

    Search results and category pages are the same listing and share these keys.

    KeyDefault
    anchor—Required. A CSS selector of the element the listing is placed relative to, or a list of candidates, most specific first
    position—Required. prepend or append inside the anchor, before or after it
    rootClass—Classes of yours put on the listing’s element, so it sits in your own grid
    settleMs—Wait until the anchor stops changing for this long — for frameworks that re-render after load
    reserveSelectorThe anchorThe element that reserves the listing’s remembered height while it loads, so the page does not jump
    holdTimeoutMs4000If the listing has not rendered by then, your own is shown instead
    showTitle—Show the query, or the category name, as a heading
    KeyDefault
    surface—Required. A search surface for search, a collection surface for category pages
    size—Required. Results per page: the first page, and each “show more”
    fieldsThe surface’sFields the tiles need. Fewer fields, smaller responses.
    baseFilters—A filter expression always applied, combined with the shopper’s filters
    KeyDefault
    facets—Required. Fields offered as filters, in sidebar order. Numeric fields become range sliders. See Facets.
    facetSize50Values per text facet
    emptyValuesfalseWith a filter applied, also list the values the unfiltered page has, marked empty, for sites that grey them out. Costs one more request per query or category.
    facetGroupsAll openopen: which groups start expanded — true, false, or the first N, optionally per viewport min-width ({ "0": false, "1024": 3 }). search: facets whose group gets a search box over its values. searchMin (10): the fewest values that get one.
    rangeSteps1The step of a range slider, by facet: { "lbx:price": 10 }
    sorts—Required. Sort options as field:direction; '' is relevance. Labels come from the translations search.sorts.
    flags—On/off filters of your own: [{ "id": "in-stock", "filter": { "in_stock": { "eq": true } } }]. Labels come from search.flags.<id>.
    facetsApplyinstantHow changes inside the filter drawer apply: instant, or staged until its apply button is pressed. Per viewport min-width too: { "0": "staged", "768": "instant" }.

    The filter drawer is your markup: data-lbx-drawer="open" on the control that opens it, data-lbx-drawer-panel on the panel, data-lbx-drawer="apply" and data-lbx-drawer="close" on its buttons.

    Facet values carry no counts.

    KeyDefault
    restoreOnBacktrueBack from a product restores the listing — every page loaded — at the tile the shopper followed, then refreshes it in the background
    prefetchNextPagetrueThe next page is fetched as the shopper nears the end, so “show more” appends at once
    contentVisibilityfalseTiles out of view skip style, layout and paint, which roughly halves a long list’s re-render. Leave it off when a tile draws outside its box — a hover panel, a badge hanging over the edge — or contains a position: fixed element.

    Set in _init.ts or _widget.ts:

    Hook
    onRender({ route, query, total, shown, page, url })After each render — to keep your document title in step, for example

    The listing’s state is in the URL, so a filtered page can be shared, bookmarked and reached with Back. Luma’s own parameters start with lbx.: lbx.sort, lbx.flag, and lbx.<field> for each facet. “Show more” does not change the URL, and a listing always opens on its first page.