Sitecore Search SDK Starter Kit: Enhanced User Experience

The Sitecore Search SDK Starter Kit provides a powerful foundation for developers to build robust and user-friendly search functionalities into their websites. This open-source project offers a significant advantage by streamlining the integration of Sitecore Search with React based applications. Recently, I have made few enhancements to the forked GitHub repository (https://github.com/Sitecore/Sitecore-Search-JS-SDK-Starter-Kit) that aim to improve the overall search experience for end users and provide developers with a more efficient development workflow.

Modular Component Architecture for Improved Maintainability and Reusability

A core aspect of the enhancements involves restructuring the codebase to utilize separate components for facets, pagination, sorting, and search results. This shift towards a modular component architecture offers several advantages:

image

Enhanced Maintainability:

Separating components fosters a well-organized codebase. This improves code readability and understanding, making it easier for developers to maintain and extend the functionalities in the future.

Increased Reusability:

Individual components can be reused across different parts of your application. This promotes code consistency and reduces development time by eliminating the need to rewrite code for similar functionalities.

Facet Refinement

Finding the exact product or information can be challenging, especially when dealing with a vast number of facets. To address this, I've introduced "show more" and "show less" functionality for facets. This allows users to control the number of facets displayed at once, preventing them from feeling overwhelmed by an excessive number of options. Additionally, facet filtering has been implemented, enabling users to refine their search results with greater precision.

image

This following component, FacetList, renders a list of facet values with filtering capabilities and a show more/show less feature. It receives props such as selectedFacetsToRender, facet, and facetsnumbertoshow, and dynamically filters the facet values based on user input. The component allows users to toggle the visibility of facet values and efficiently manage large lists by displaying only a subset at a time.

1import { CheckIcon } from '@radix-ui/react-icons';
2import type { SearchResponseFacet } from '@sitecore-search/react';
3import { AccordionFacets } from '@sitecore-search/ui';
4import { useEffect, useState } from 'react';
5import type { SelectedFacets } from '../Facets';
6import { AccordionFacetsStyled } from '../styled';
7export interface FacetListType {
8  facet: SearchResponseFacet;
9  selectedFacetsToRender: SelectedFacets[];
10  facetsnumbertoshow: number;
11}
12
13export const FacetList = ({ selectedFacetsToRender, facet, facetsnumbertoshow }: FacetListType) => {
14  const isSelected = (facetID: string, facetValue: string) => {
15    return (
16      selectedFacetsToRender.filter(
17        (x) => x.id === facetID && x.values.map((q) => q.id).includes(facetValue)
18      ).length > 0
19    );
20  };
21
22  const minNumberOfItemsToShow = facetsnumbertoshow ?? 5;
23  const totalItems = facet.value.length;
24  const [keyword, setKeyword] = useState('');
25  const [filteredItems, setFilteredItems] = useState(facet.value);
26  const [numberOfItemsToShow, setNumberOfItemsToShow] = useState(minNumberOfItemsToShow);
27
28  useEffect(() => {
29    // This will be called whenever parentProp changes (i.e., when the parent component rerenders)
30    setFilteredItems(facet.value);
31  }, [facet.value]);
32
33  const handleInputChange = (event: { target: { value: string } }) => {
34    const inputKeyword = event.target.value.toLowerCase();
35    setKeyword(inputKeyword);
36
37    // Filter the array based on the input keyword
38    const updatedItems = facet.value.filter((item) =>
39      item.text.toLowerCase().includes(inputKeyword)
40    );
41    setFilteredItems(updatedItems);
42  };
43
44  const handleShowMore = () => {
45    setNumberOfItemsToShow((prevVisibleItems) => prevVisibleItems + minNumberOfItemsToShow);
46  };
47
48  const handleShowLess = () => {
49    setNumberOfItemsToShow((prevVisibleItems) =>
50      Math.max(prevVisibleItems - minNumberOfItemsToShow, minNumberOfItemsToShow)
51    );
52  };
53
54  return (
55    <>
56      <AccordionFacetsStyled.Facet facetId={facet.name} key={facet.name}>
57        <AccordionFacets.Content>
58          <div className="input_wrap">
59            <input
60              name={facet.name}
61              placeholder="Type to filter..."
62              id={facet.name}
63              type="text"
64              value={keyword}
65              onChange={handleInputChange}
66            />
67          </div>
68          <AccordionFacetsStyled.ValueList>
69            {filteredItems.slice(0, numberOfItemsToShow).map((v, index) => (
70              ...
71            ))}
72          </AccordionFacetsStyled.ValueList>
73
74          {filteredItems.length > minNumberOfItemsToShow && (
75            <div className="retractable-actions">
76              {numberOfItemsToShow < totalItems && (
77                <a href="#" className="retractable-toggle"
78                  onClick={(e) => {
79                    e.preventDefault();
80                    handleShowMore();
81                  }} > Show More{' '}
82                </a>
83              )}
84              <br />
85              {numberOfItemsToShow > minNumberOfItemsToShow && (
86                <a href="#" className="retractable-toggle"
87                  onClick={(e) => {
88                    e.preventDefault();
89                    handleShowLess();
90                  }} > {' '} Show Less
91                </a>
92              )}
93            </div>
94          )}
95        </AccordionFacets.Content>
96      </AccordionFacetsStyled.Facet>
97    </>
98  );
99};
100
101export default FacetList;

Sharable Search Queries

Imagine collaborating with colleagues on research or revisiting a complex search later. The implemented mechanism to append facet selections and page numbers to the query string makes this a reality. Users can now generate URLs that include preselected facets and specific pages, Simply revisit the shared URL, and your desired search criteria are instantly applied.

image

Following is the function responsible to generate query string and append in Query string, called when any facet value is clicked.

This TypeScript function, manages the modification of facet-related search parameters in a URL query string. It parses the current query parameters, updates facet values based on user actions (such as selecting or deselecting options), and generates an updated URL with the modified parameters, ultimately navigating to the new URL

1const updateFacetsSearchParams = (params: any, remove = false) => {
2    const queryParams = new URLSearchParams(location.search);
3    const searchParamsObject = paramsToObject(queryParams.entries()) as any;
4    let values = searchParamsObject[params.facetId]?.split(',') ?? [];
5    values = values.filter((n: any) => n);
6    if (remove || params.checked === false) {
7      const index = values.indexOf(params.facetValueId);
8      if (index > -1) {
9        values.splice(index, 1);
10      }
11    } else {
12      values.push(params.facetValueId);
13    }
14    if (values.length <= 0) {
15      delete searchParamsObject[params.facetId];
16    }
17    delete searchParamsObject.page;
18    searchParamsObject[params.facetId] = removeDuplicates(values).join(',');
19    const updatedRelativeUrl = generateQueryString('/search', searchParamsObject);
20    navigate(updatedRelativeUrl);
21  };

Open-Source Contribution and Continued Development

All of the enhancements mentioned above are included in a pull request submitted to the forked GitHub repository: https://github.com/mgnventures/Sitecore-Search-TS-SDK-Starter-Kit/pull/1 . This pull request provides a detailed overview of the changes and facilitates the integration of these improvements into the forked Sitecore Search SDK Starter Kit.

I believe these enhancements will significantly improve the Sitecore Search SDK Starter Kit, providing developers with a more efficient development experience and empowering users with a more intuitive and productive search experience. If you're interested in learning more or contributing to this project, feel free to visit the GitHub repository.

Related Posts

Leveraging Sitecore Search SDK Starter Kit into Your Sitecore Next.js Solution [Part 2]

In this blog post, I'll walk you through the process of smoothly leveraging the Search SDK Starter Kit into a Sitecore Next.js solution. ## Prerequisites Before proceeding, ensure the following prer

Read More

Sitecore Search SDK Integration [Part 1]

In today's web development landscape, delivering efficient and intuitive search functionality is crucial to provide an enhanced user experience for your visitors. With the advent of Sitecore Search,

Read More

Sitecore Search SDK Starter Kit: Enhanced User Experience

The Sitecore Search SDK Starter Kit provides a powerful foundation for developers to build robust and user-friendly search functionalities into their websites. This open-source project offers a signi

Read More