Recipes

Complete storefront code for two common layouts, one facet of your own and filters in a sheet on a phone.

Each recipe is complete code for the home store, built on Your storefront and the React components.

One facet in a layout of your own

FacetFilter draws one facet of an answer and hands the shopper's choice back to you. Here it draws the sofa page's colors; pick one to see the filters a storefront would send:

PreviewFacetFilter

Farbe

Filters {}

app/color-filter.tsx
import type {  } from "@orbsearch/client";
import { , , type  } from "@orbsearch/react";

type  = {
    : readonly [];
    : ;
    : (: ) => void;
};

export function ({ , ,  }: ) {
    const  = .(() => . === "color");
    if ( === ) return null;

    return (
        <
            ={}
            ={.color}
            ={() => ((, "color", ))}
        />
    );
}

The facet comes from the listed section's facets, as the sofa page answers it:

Terminal
curl -s 'http://127.0.0.1:7800/v1/search?on=category_page&category=wohnen/sofas' \
  | jq '.sections[] | select(.type == "product") | .facets[] | select(.field == "color")'
200 · 14 ms · release b25a6aaa
{
  "field": "color",
  "kind": "swatch",
  "label": "Farbe",
  "values": [
    {
      "value": "anthracite",
      "label": "Anthrazit",
      "count": 2,
      "swatch": "#3B3F42"
    },
    {
      "value": "beige",
      "label": "Beige",
      "count": 2,
      "swatch": "#D9C4A3"
    },
    {
      "value": "grey",
      "label": "Grau",
      "count": 2,
      "swatch": "#9B9B9B"
    },
    {
      "value": "green",
      "label": "Grün",
      "count": 2,
      "swatch": "#5F7A4A"
    }
  ],
  "custom_display": "color_tiles"
}

withField sets one field of the filters and drops it when the shopper clears it. The color facet names its own display in custom_display, which a storefront draws with yours (Facet displays).

Reference: facets in an answer

Filters in a sheet on a phone

ListingPage moves its filters into a sheet on a phone by itself. With filters="sidebar", the panel beside the results gives way to a "Filter" button below 64rem:

app/routes/shop.tsx
< ={} ="sidebar" />;

With the default bar, "Filter" opens every facet in the same sheet. Choices there wait for its button, "Ergebnisse anzeigen" (show results), whose count follows the pending choice. Escape or the close button discard them. Without script the sheet cannot open, so the panel's plain form shows on every screen.

In a layout of your own, FilterSheet takes the facets and the listing's state from useListing:

app/filters.tsx
import { , , type  } from "@orbsearch/react";

export function ({  }: { :  }) {
    const  = ();

    return (
        <
            ={.}
            ={.}
            ={.}
            ={.}
            ={.}
            ={.}
        />
    );
}

For a dialog of your own, useFilters holds the pending choice apart from the applied one and counts it, a moment after the shopper stops choosing:

app/filter-dialog.tsx
import { , , , type , type  } from "@orbsearch/react";

type  = { : ; : ; : () => void };

export function ({ , ,  }: ) {
    const {  } = ();
    const  = ({ : ., : ., : ., : . });

    return (
        <
            ={() => {
                .();
                .();
                ();
            }}
        >
            < ={.} ={.} ={.} />
            < ="submit" ={.}>
                {..(.)}
            </>
        </>
    );
}

page is what useListing(listing) returned in the page that opens the dialog. filters.start() begins again from the applied filters, as a dialog does each time it opens.

Next

  • Theming: give the shop its look.
  • Accessibility: what the pages do for keyboard and screen reader users, and what stays yours.
  • Clicks and views: what the pages report for Insights.

On this page