useSearch

The useSearch hook enables searching with pagination. It’s ideal for traditional searches with pagination where users navigate between pages using page numbers.

Configuration

To use the hook, you can provide the searchIndexId and the search query.

RequestResponse
import { useSearch } from '@sitecore-content-sdk/nextjs/search';

const { results } = useSearch({
  searchIndexId: '<YOUR_SEARCH_INDEX_ID>',
  query: 'product'
});

Supported parameters

The hook expects the ID of the search index and also supports several other parameters used to sort, paginate, keep previous search data, etc.

Parameter

Type

Description

searchIndexId

string

The ID of the SitecoreAI search index to retrieve results from.

Required

query

string

Specify a query to search the index for specific content.

page

number

Specify the page number to retrieve results from. It is 1-indexed, meaning it starts from 1, 2, 3... and so on, and defaults to 1 when empty.

pageSize

number

Specify the number of results per page.

sort

RequestResponse
{
name: string;
order: "asc" | "desc"
}
OR
Array<{
name: string;
order: "asc" | "desc"
}>;

Specify an object or array of objects containing the name and order to sort results by.

enabled

boolean

Specify whether to run a manual search.

keepPreviousData

boolean

Specify whether previous search results should be kept when performing a new search.

Examples

The hook contains all traditional searching capabilities like sorting (single, multi-field, and nested fields), pagination, manual search execution, and keeping previous data while searching. The hook also supports TypeScript generics that lets you define the shape of your search results for type safety.

Simple search with keyphrase

A basic search requires only the searchIndexId. You can specify additional parameters as needed.

RequestResponse
import { useSearch } from '@sitecore-content-sdk/nextjs/search';

function BasicSearch() {
  const { results } = useSearch({
    searchIndexId: '<YOUR_SEARCH_INDEX_ID>',
    query: 'product',
  });

  return (
    <div>
      <p>Found {results.length} results</p>
      {results.map((item) => (
        <div key={item.id}>
          <h2>{item.name}</h2>
          <p>{item.description}</p>
        </div>
      ))}
    </div>
  );
}

Search with a generic type

The useSearch hook supports TypeScript generics, allowing you to define the shape of your search document for type safety and better IDE support.

RequestResponse
import { useSearch } from '@sitecore-content-sdk/nextjs/search';

type Product = {
  id: string;
  name: string;
  description: string;
  price: number;
  category: string;
};

function ProductSearch() {
  const { results, isLoading, total, totalPages, error } = useSearch<Product>({
    searchIndexId: 'your-search-index-id',
    query: 'product',
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <p>Found {results.length} results</p>
      <p>Total pages: {totalPages}</p>
      <p>Total results: {total}</p>
      {results.map((product) => (
        <div key={product.id}>
          <h2>{product.name}</h2>
          <p>{product.description}</p>
        </div>
      ))}
    </div>
  );
}

Search with pagination

The useSearch hook supports pagination through the page parameter. The hook automatically calculates the offset based on the page number and page size:

RequestResponse
import { useState } from 'react';
import { useSearch } from '@sitecore-content-sdk/nextjs/search';

type Product = {
  id: string;
  name: string;
  price: number;
  rating: number;
  category: string;
};

function PaginatedSearch() {
  const [currentPage, setCurrentPage] = useState(1);
  const pageSize = 20;

  const { results, isLoading, total, totalPages } = useSearch<Product>({
    searchIndexId: 'your-search-index-id',
    query: 'product',
    page: currentPage,
    pageSize,
  });

  const handlePreviousPage = () => {
    if (currentPage > 1) {
      setCurrentPage(currentPage - 1);
    }
  };

  const handleNextPage = () => {
    if (currentPage < totalPages) {
      setCurrentPage(currentPage + 1);
    }
  };

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <div>
        {results.map((result) => (
          <div key={result.id}>{result.name}</div>
        ))}
      </div>

      <div>
        <button onClick={handlePreviousPage} disabled={currentPage === 1}>
          Previous
        </button>
        <span>
          Page {currentPage} of {totalPages}
        </span>
        <button onClick={handleNextPage} disabled={currentPage === totalPages}>
          Next
        </button>
      </div>

      <p>
        Showing {results.length} of {total} results
      </p>
    </div>
  );
}

Search with basic sorting

The hook supports sorting results using a single sort object specifying the name and order. The following example sorts the search results by the price in the ascending order (lowest first).

RequestResponse
import { useSearch } from '@sitecore-content-sdk/nextjs/search';

type Product = {
  id: string;
  name: string;
  price: number;
  rating: number;
  category: string;
};

function ProductSearch() {
  const { results } = useSearch<Product>({
    searchIndexId: '<YOUR_SEARCH_INDEX_ID>',
    query: 'laptop',
    sort: {
      name: 'price',
      order: 'asc',
    },
  });

  ... rest of the code ...
}

Search with multi-field sorting

You can also specify multiple fields to sort. Instead of a single object, you should specify this as an array of objects. The following example sorts the search results by category in the ascending order, followed by price in ascending order, and finally by rating in the descending order.

RequestResponse
const { results } = useSearch<Product>({
  searchIndexId: '<YOUR_SEARCH_INDEX_ID>',
  query: 'electronics',
  sort: [
    {
      name: 'category',
      order: 'asc', // First sort by category
    },
    {
      name: 'price',
      order: 'asc', // Then by price within each category
    },
    {
      name: 'rating',
      order: 'desc', // Finally by rating (highest first)
    },
  ],
});

Search with nested field sorting

Using dot notation (.), you can sort nested properties.

RequestResponse
import { useSearch } from '@sitecore-content-sdk/nextjs/search';

type Order = {
  id: string;
  orderDate: string;
  customer: {
    name: string;
    email: string;
  };
  total: number;
};

const { results } = useSearch<Order>({
  searchIndexId: '<YOUR_SEARCH_INDEX_ID>',
  query: 'order',
  sort: {
    name: 'customer.name', // Sort by nested property using dot notation
    order: 'asc',
  },
});

Search while keeping previous data

You can keep your existing search results while performing a new search by enabling the keepPreviousData parameter. This provides a better user experience when executing search queries.

RequestResponse
const { results, isLoading, isPreviousData } = useSearch({
  searchIndexId: '<YOUR_SEARCH_INDEX_ID>',
  query: 'product',
  keepPreviousData: true, // Keep previous results while loading
});

// isPreviousData is true when showing previous results during loading
// ... rest of the code ...

You can perform a manual search by setting the enabled parameter to true. This is useful when you want the user to type in a query and click a button to perform the search.

RequestResponse
import { useState } from 'react';
import { useSearch } from '@sitecore-content-sdk/nextjs/search';

type Article = {
  id: string;
  title: string;
};

function ManualSearch() {
  const [query, setQuery] = useState('');
  const [enabled, setEnabled] = useState(false);

  const { results, isLoading } = useSearch<Article>({
    searchIndexId: 'your-search-index-id',
    query,
    enabled, // Don't search automatically
  });

  const handleSearch = () => {
    setEnabled(true);
  };

  return (
    <div>
      <button onClick={handleSearch}>Search</button>
      ... rest of the code ...
      {enabled && (
        <>
          {isLoading ? (
            <div>Searching...</div>
          ) : (
            <ul>
              {results.map((result) => (
                <li key={result.id}>{result.title}</li>
              ))}
            </ul>
          )}
        </>
      )}
    </div>
  );
}

Do you have some feedback for us?

If you have suggestions for improving this article,