VTEX Search Result

Build Status
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
All Contributors
<!-- ALL-CONTRIBUTORS-BADGE:END -->

Description

The VTEX Search Result app is a store component that handles with the result of our Search API, and this app is used by store theme.

📢 Disclaimer: Don't fork this project; use, contribute, or open issue with your feature request.

Supported Blocks

This are the current supported blocks in this repository. Blocks not mentioned are deprecated.

Block nameComponentDescription
galleryGalleryGallery that displays found products
not-foundNotFoundSearchBlock containing text and description that search was not found
search-result-layoutSearchResultLayoutLayout block that enables user to build a custom search page
search-result-layout.customQuerySearchResultLayoutCustomQueryJust like search-result-layout but accepts a querySchema prop to execute custom query.
search-result-layout.desktopSearchResultFlexibleBlock used to build layout for desktop.
search-result-layout.mobileSearchResultFlexibleMobileBlock used to build layout for mobile.
search-not-found-layoutNotFoundLayoutBlock used to layout when a user searches for a product that does not exist.
search-layout-switcherLayoutModeSwitcherFlexibleEnables user to switch between layout modes in mobile
search-contentSearchContentBlock that chooses to show the gallery block if products are found and not-found if filters selected lead to an empty search
search-fetch-moreFetchMoreRenders the fetch more button if pagination is of type show-more. If it is infinite scroll, shows the Loader when bottom of the page is reached
search-fetch-previousFetchPreviousRenders the fetch previous button.
search-products-count-per-pageProductCountPerPageShows the total count of products displayed in search at the moment.
order-by.v2OrderByFlexibleAllows user to pick the type of order of the products displayed.
filter-navigator.v3FilterNavigatorFlexibleAllows user to apply different filters to search. On mobile, renders a button that shows the sidebar when pressed.
total-products.v2TotalProductsFlexibleShows the total products count found for that search.
search-title.v2SearchTitleFlexibleDisplay search title according to the search context.

Flexible Layout Update

search-result now supports a flexible layout and has all its benefits, specially using the flex-layout block.

You now have access to search-result-layout, it supports three different blocks: search-result-layout.desktop, search-result-layout.mobile, search-not-found-layout.

search-result-layout.desktop is rendered when user is using a desktop. The .mobile interface is rendered (if provided), when user is using a mobile device. If the .mobile is not provided, the .desktop will be used.

The search-not-found-layout is used (if provided) when the user searches for a term that returns nothing.

Important notice: if the user lands on a search page and adds filters until it reachs a empty search, this block will not be rendered! Instead, the not-found component, which is currently not flexible, will.

We also created the search-result-layout.customQuery. If you want to display a custom search-result, by passing a custom querySchema, this block should be used. search-result-layout does not read the values of a querySchema prop!

To pass parameters to the search displayed at search-result-layout you should use the context props in store.search. Example:

"store.search": {
    "blocks": [
      "search-result-layout"
    ],
    "props": {
        "context": {
           "orderByField": "OrderByReleaseDateDESC",
            "hideUnavailableItems": true,
            "maxItemsPerPage": 8,
            "skusFilter": "FIRST_AVAILABLE"
        }
     }
  },

If you want to use the .customQuery:

"store.home": {
  "blocks": [
    "carousel#home",
     "shelf#home",
    "search-result-layout.customQuery#home"
  ]
},
"search-result-layout.customQuery#home": {
  "props": {
    "querySchema": {
      "orderByField": "OrderByReleaseDateDESC",
      "hideUnavailableItems": true,
      "maxItemsPerPage": 8,
      "queryField": "clothing",
      "mapField": "c",
      "skusFilter": "FIRST_AVAILABLE"
    }
  },
  "blocks": ["search-result-layout.desktop"]
}

In order to be used inside the flexible block, we created: breadcrumb.search, search-fetch-more, search-fetch-previous, search-content, search-products-count-per-page, filter-navigator.v3, total-products.v2, order-by.v2 & search-title.v2.

Noticeable notes:

  • search-fetch-more renders the fetch more button. Infinite-scroll was deprecated.
  • search-content renders the gallery or the not-found block, depending on the products returned for the specified filters.
  • search-products-count-per-page renders the current products count displayed.
  • All *.v2 or .v3 is just a version bump, no changes in behaviour, the changes are that the new components now fetch the data from the search page context and should only be used in the flexible layout. Also changes the wrapper css class, usually by just adding a --layout to the previous used class (like filters to filters--layout).

Read more at the Max Items Per Page Usage section.

Important Note

We ask for users, from now on, to use the filter-navigator.v2 block if you want to keep updated with the most up to date Filter Navigator in your search-result.

The correct way to use it is setting it in your blocks.json like:

json
"search-result": {
    "blocks": [
      "filter-navigator.v2",
      "gallery",
      "not-found",
      "breadcrumb",
      "order-by",
      "total-products"
    ],
  }

Or via Storefront.

Max Items Per Page Usage

Disclaimer: this notice is deprecated, please use the search-result-layout block. A search-result block may appear in two different contexts, (a) in a search result page (store.search) or (b) as a block in your home page (store.home).

In case of (a) we can configure the search parameters in a search context in the following way:

  "store.search": {
    "blocks": [
      "search-result"
    ],
    "props": {
        "context": {
           "orderByField": "OrderByReleaseDateDESC",
            "hideUnavailableItems": true,
            "maxItemsPerPage": 8,
            "skusFilter": "FIRST_AVAILABLE"
        }
     }
  },
 "store.search#category": {
    "blocks": [
      "search-result"
    ],
    "props": {
        "context": {
           "orderByField": "OrderByReleaseDateDESC",
            "hideUnavailableItems": true,
            "maxItemsPerPage": 8,
            "skusFilter": "FIRST_AVAILABLE"
        }
     }
  },
  "store.search#brand": {
    "blocks": [
      "search-result"
    ],
    "props": {
        "context": {
           "orderByField": "OrderByReleaseDateDESC",
            "hideUnavailableItems": true,
            "maxItemsPerPage": 8,
            "skusFilter": "FIRST_AVAILABLE"
        }
     }
  },
  "store.search#department": {
    "blocks": [
      "search-result"
    ],
    "props": {
        "context": {
           "orderByField": "OrderByReleaseDateDESC",
            "hideUnavailableItems": true,
            "maxItemsPerPage": 8,
            "skusFilter": "FIRST_AVAILABLE"
        }
     }
  },
  "store.search#subcategory": {
    "blocks": [
      "search-result"
    ],
    "props": {
        "context": {
           "orderByField": "OrderByReleaseDateDESC",
            "hideUnavailableItems": true,
            "maxItemsPerPage": 8,
            "skusFilter": "FIRST_AVAILABLE"
        }
     }
  }

Note that only in this case, the parameters must be passed in the context prop of the store.search block. Also remember that we have different store.search blocks and you may configure them in different ways. You may configure a brand search (ended with /b), have 6 items per page, while a department search page, that number may be 12.

Search examples: Free search: https://storetheme.vtex.com/shirt?map=ft. Falls on: store.search. Departament: https://storetheme.vtex.com/decoration/d. Falls on: store.search#department. Category: https://storetheme.vtex.com/bags/necessaire. Falls on: store.search#category Subcategory: https://storetheme.vtex.com/decoration/smartphones/bateria. Falls on:store.search#subcategory. Brand: https://storetheme.vtex.com/kawasaki/b. Falls on:store.search#brand`.

Now for option (b), when we want to show the search-result block outside of a search page, like in the home page, the same parameters must be passed on a different way.

At our example, we want to show a search-result inside a store.home. We put this inside our blocks.json:

"store.home": {
  "blocks": [
    "carousel#home",
    "shelf#home",
    "search-result#home"
  ]
}

Now, to change the search done by this block, we must pass its parameters directly to it, thorugh the querySchema prop:

"store.home": {
  "blocks": [
    "carousel#home",
     "shelf#home",
    "search-result#home"
  ]
},
"search-result#home": {
  "props": {
    "querySchema": {
      "orderByField": "OrderByReleaseDateDESC",
      "hideUnavailableItems": true,
      "maxItemsPerPage": 8,
      "skusFilter": "FIRST_AVAILABLE"
    }
  }
}

Release schedule

ReleaseStatusInitial ReleaseMaintenance LTS StartEnd-of-lifeStore Compatibility
3.xCurrent Release2018-12-012.x
2.xMaintenance LTS2018-10-022018-12-01March 20191.x

See our LTS policy for more information.

Table of Contents

Usage

This app uses our store builder with the blocks architecture. To know more about Store Builder click here.

We add the search-result as a block in our Store.

To configure or customize this app, you need to import it in your dependencies in manifest.json.

  dependencies: {
    "vtex.search-result": "3.x"
  }

Then, add search-result block into your app theme as we do in our Store theme app.

Now, you can change the behavior of the search result block that is in the store header. See an example of how to configure:

  "search-result#department": {
    "blocks": [
      "filter-navigator.v2",
      "gallery",
      "not-found",
      "breadcrumb",
      "order-by",
      "total-products",
      "search-title"
    ],
    "props": {
      "context": {
        "maxItemsPerPage": 2,
        "orderByField": "OrderByReleaseDateDESC"
      },
      "hiddenFacets": {
        "layoutMode1": "normal",
        "layoutMode2": "small",
        "specificationFilters": {
          "hiddenFilters": []
        }
      },
      "pagination": "show-more"
    }
  },

Blocks API

When implementing this app as a block, various inner blocks may be available. The following interface lists the available blocks within search result and describes if they are required or optional.

"search-result": {
    "allowed": [
      "not-found",
      "breadcrumb",
      "filter-navigator",
      "total-products",
      "order-by",
      "search-title"
    ],
    "required": [
      "gallery"
    ],
    "component": "index"
  },

The search-result has as a required block the gallery. So, any search-result block implementation created must add a gallery as a block that is inside of search-result. Similarly, gallery has its own inner block structure that can be configured that you can see below.

 "gallery": {
    "required": [
      "product-summary"
    ],
    "component": "Gallery"
  }

The gallery has as a required block the product-summary. So, any gallery block implementation created must add a product-summary as a block that is inside of gallery. (Similarly, product-summary has its own inner block structure that can be configured. There is a link to its API in the next section.)

Configuration

Layout API

These properties can be changed in the blocks.json file of your theme.

Prop nameTypeDescriptionDefault value
querySchemaQuerySchemaQuery made when there's no contextN/A
hiddenFacetsHiddenFacetsIndicates which facets will be hiddenN/A
paginationEnumPagination type (values: 'show-more' or 'infinite-scroll')infinity-scroll
mobileLayoutMobileLayoutControl mobile layoutN/A
showFacetQuantityBooleanIf quantity of items filtered by facet should appear besides its name on filter-navigatorfalse
blockClassStringUnique class name to be appended to block classes""
showProductsCountBooleancontrols if the quantity of loaded products and total number of items of a search result are displayed under the show more button.false
QuerySchema
Prop nameTypeDescriptionDefault value
maxItemsPerPageNumberMaximum number of items per search page10
queryFieldStringQuery fieldN/A
mapFieldStringMap fieldN/A
restFieldStringOther Query StringsN/A
orderByFieldEnumOrder by field (values: OrderByTopSaleDESC, OrderByReleaseDateDESC, OrderByBestDiscountDESC, OrderByPriceDESC, OrderByPriceASC, OrderByNameASC, OrderByNameDESC or '' (by relevance))''
hideUnavailableItemsBooleanSet if unavailable items should show on searchfalse
skusFilterSkusFilterEnumControl SKUs returned for each product in the query. The less SKUs needed to be returned, the more performant your shelf query will be."ALL_AVAILABLE"

SkusFilterEnum: | Name | Value | Description | | ---- | ----- | ----------- | | First Available | FIRST_AVAILABLE | Most performant, ideal if you do not have a SKU selector in your shelf. Will return only the first available SKU for that product in your shelf query. | | All Available | ALL_AVAILABLE | A bit better performace, will only return SKUs that are available, ideal if you have a SKU selector but still want a better performance. | | All | ALL | Returns all SKUs related to that product, least performant option. |

HiddenFacets
Prop nameTypeDescriptionDefault value
brandsBooleanHide Brands filterfalse
categoriesBooleanHide Categories filterfalse
priceRangeBooleanHide Price filterfalse
specificationFiltersSpecificationFiltersHide Specifications filtersN/A
SpecificationFilters
Prop nameTypeDescriptionDefault value
hideAllBooleanHide specifications filtersfalse
hiddenFiltersArray(HiddenFilterUnit)Array of specifications filters that should be hiddenN/A
HiddenFilterUnit
Prop nameTypeDescriptionDefault value
nameString!Name of Hidden specification filter""
MobileLayout

This prop controls the way search results are displayed on mobile. The default values are shown below.

Notice that the default behavior for your store will be the one defined by the mode1. If you want the user to be able to switch between two modes, you must specify the mode2 prop. If only the mode1 is provided, the layout switcher will not be shown and search results will always be rendered according to mode1.

Prop nameTypeDescriptionDefault value
mode1EnumLayout mode of the switcher (values: 'normal', 'small' or 'inline')normal
mode2EnumLayout mode of the switcher 2 (values: 'normal', 'small' or 'inline')small
filter-navigator block
Prop nameTypeDescriptionDefault value
preventRouteChangeBooleanPrevents route change when selecting filters, using the query string instead. Intended for search-result blocks inserted on custom pages with static routes.false
initiallyCollapsedBooleanMakes the search filters start out collapsed.false
filter-navigator.v2 block
Prop nameTypeDescriptionDefault value
preventRouteChangeBooleanPrevents route change when selecting filters, using the query string instead. Intended for search-result blocks inserted on custom pages with static routes.false
initiallyCollapsedBooleanMakes the search filters start out collapsed.false

Also, you can configure the product summary that is defined on search-result. See here the Product Summary API.

order-by block
Prop nameTypeDescriptionDefault value
hiddenOptionsArray(String)Indicates which sort options will be hidden. (e.g. ["OrderByNameASC", "OrderByNameDESC"])[]
SORT_OPTIONS
OptionValue
Relevance""
Top Sales Descending"OrderByTopSaleDESC"
Release Date Descending"OrderByReleaseDateDESC"
Best Discount Descending"OrderByBestDiscountDESC"
Price Descending"OrderByPriceDESC"
Price Ascending"OrderByPriceASC"
Name Ascending"OrderByNameASC"
Name Descending"OrderByNameDESC"

Styles API

This app provides some CSS classes as an API for style customization.

To use this CSS API, you must add the styles builder and create an app styling CSS file.

  1. Add the styles builder to your manifest.json:
  "builders": {
    "styles": "1.x"
  }
  1. Create a file called vtex.searchResult.css inside the styles/css folder. Add your custom styles:
.container {
  margin-top: 10px;
}

CSS namespaces

Below, we describe the namespaces that are defined in the search-result.

Token nameDescriptionComponent Source
containerThe main container of search-resultSearchResult
buttonShowMoreShow the see more buttonShowMoreLoaderResult
showingProductsText below the show mnore buttonShowMoreLoaderResult
showingProductsCountThe range part of the text below the show more buttonShowMoreLoaderResult
switchLayout mode switcher containerSearchResult
breadcrumbBreadcrumb containerSearchResult
filterFilter option containerFilterOptionTemplate
resultGalleryGallery result containerSearchResult
borderOrder by container borderSearchResult
galleryThe main container of galleryGallery
filterPopupButtonFilter pop-up buttonFilterSideBar
accordionFilterAccordion filter containerAccordionFilterContainer
filterAccordionItemBoxAccordion filter item containerAccordionFilterItem
filterAccordionBreadcrumbsFilter accordion breadcrumbs containerAccordionFilterContainer
filterButtonsBoxFilter buttons containerFilterSidebar
filterPopupFooterFilter pop-up footer containerPopup
accordionFilterItemOptionsAccordion filter item options containerAccordionFilterItem
dropdownMobileThe main container of drop-down on mobileSelectionListOrderBy
accordionFilterItemActiveContainer of the accordion filter item when it is activeAccordionFilterItem
totalProductsThe main container of total-productsTotalProducts
orderByThe main container of order-byOrderBy
accordionFilterItemHiddenAccordion filter item container when it is hiddenAccordionFilterItem
accordionFilterItemAccordion filter item containerAccordionFilterItem
accordionFilterItemBoxAccordion filter item boxAccordionFilterItem
accordionFilterItemTitleAccordion filter item title containerAccordionFilterItem
accordionFilterItemIconAccordion filter item icon containerAccordionFilterItem
filterAvailableFilter option template main container when it is availableFilterOptionTemplate
filterSelectedFilter option template main container when it is selectedFilterOptionTemplate
filterPopupTitleFilter pop-up title labelFilterSidebar
filterPopupArrowIconFilter pop-up arrow icon containerFilterSidebar
footerButtonFooter buttonFooterButton
layoutSwitcherLayout mode switcher containerLayoutModeSwitcher
filterPopupMain container of filter pop-upFilterPopup
filterPopupOpenMain container of filter pop-up when it is openFilterPopup
filterPopupContentFilter pop-up contentPopup
filterPopupContentContainerFilter pop-up content containerPopup
filterPopupContentContainerOpenFilter pop-up content container when it is openPopup
galleryItemGallery item containerGallery
searchNotFoundMain container of Search Not FoundNotFoundSearch
filterContainerFilter containerFilterNavigator
filterContainer--titleTitle's filter containerFilterNavigator
filterContainer--selectedFiltersSelected filters' filter containerSelectedFilters
filterContainer--cDepartment's filter containerDepartmentFilters
filterContainer--bBrand's filter containerFilterOptionTemplate
filterContainer--priceRangePrice range's filter containerPriceRange
filterContainer-- + FACET_TYPEFACET_TYPE's filter containerFilterOptionTemplate
filterTitleFilter title containerFilterOptionTemplate
filterIconFilter icon containerFilterOptionTemplate
galleryTitleCategory name or search term titleTitle
filterItemCheckbox and label for Filters (desktop only)SearchFilter
filterItem-- + FACET_VALUEFACET_VALUE's checkbox and label for Filters (desktop only)SearchFilter
filterItem--selectedCheckbox and label for selected Filters (desktop only)SearchFilter
selectedFilterItemCheckbox and label for selected Filters (desktop only)SelectedFilters
orderByButtonthe "Sort By" button found on search resultsSelectionListOrderBy
orderByDropdownthe dropdown that appears when the "Sort By" button found on search results is pressedSelectionListOrderBy
orderByOptionsContainerthe container with the "Order by" options of the "Sort by" buttonSelectionListOrderBy
orderByOptionItemthe "Order by" option that appears in the container of the "Sort by" buttonSelectionListOrderBy

| categoriesContainer | The container for the department filters | DepartmentFilters | | categoryGroup | Container for each category group in the department filters | CategoryFilter | | categoryParent | View of the parent category of this group | CategoryFilter |

Troubleshooting

You can check if others are experiencing similar issues here. Also feel free to open issues.

Contributing

Check it out how to contribute with this project.

Tests

To execute our tests go to react/ folder and run npm test

Contributors ✨

Thanks goes to these wonderful people (emoji key):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --><!-- prettier-ignore-start --><!-- markdownlint-disable --><table> <tr> <td align="center"><a href="https://github.com/grupo-exito-ecommerce"><img src="https://avatars2.githubusercontent.com/u/46934781?v=4" width="100px;" alt="grupo-exito-ecommerce"/><br /><sub><b>grupo-exito-ecommerce</b></sub></a><br /><a href="https://github.com/vtex-apps/search-result/commits?author=grupo-exito-ecommerce" title="Code">💻</a></td> </tr> </table><!-- markdownlint-enable --><!-- prettier-ignore-end --><!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the all-contributors specification. Contributions of any kind welcome!