Create a simple search in Next.js

In this part we will look into building a simple search functionality with along with handling the search query from the server and returning the relevant response to the user.

Create a simple search in Next.js

This tutorial is part of the multipart tutorial on building a full stack epic game store inspired app with Next.js.

In this part we will look into building a simple search functionality with along with handling the search query from the server and returning the relevant response to the user.

Creating the search field

To achieve the result in Next.js the search field consists of a client side input field coupled with a React state, I also used the useDebounse hook to wait for a bit of time before I launch a new search query.

The final part of the search field is using the client side router to navigate to the search page with the embedded search query.

'use client'

function SearchBar({ className, basePath, onSearchChange }: Props) {
  const router = useRouter()

  const [searchValue, setSearchValue] = useState<string | null>(null)
  const [query] = useDebounce(searchValue, 300)
  const pathName = usePathname()
  const q = useSearchParams()

  const currentPath = basePath ? basePath : pathName.split('/').pop()
  const defaultValue = q.get('q') || ''

  useEffect(() => {
    if (query) {
      router.push(`/${currentPath}?q=${searchValue}`)
    } else if (!query && searchValue === '') {
      router.push(`/${currentPath}`)
    }
  }, [query, router, currentPath, searchValue])

  const handleSearch = (value: string) => {
    onSearchChange ? onSearchChange('q', value) : setSearchValue(value)
  }
  return (
        <Input
          defaultValue={defaultValue}
          className={cn(' w-full max-w-xs pr-10', className)}
          placeholder="Search the library"
          onChange={(e) => {
            handleSearch(e.target.value)
          }}
        />
  )
}

Next part we add the search component to our top level layout, in the code below I added it to the Navbar component that lives in the top layout, making it visible in all pages.

function Navbar() {
  return (
    <div className="flex justify-between items-center mb-8 gap-4">
      <div className="flex gap-4">
        <SearchBar basePath="search" />
      </div>
      <UserButton
        afterSignOutUrl="/"
        userProfileMode="navigation"
        userProfileUrl="/user-profile"
      />
    </div>
  )
}

export default Navbar

Handling the server response

Using this flow we know that the search page can have a search query, we can use the queries to fetch the relevant result and render the page to the user with them the code below shows the process.

type Props = {
  searchParams?: { [key: string]: string | string[] | undefined }
}

async function SearchPage({ searchParams }: Props) {
  const searchQuery = searchParams?.q || null

  return (
    {
    searchQuery ? <searchResults query={searchQuery} />
    }
  )
}

export default SearchPage

And there you have it, this is the simplest way I found to add search functionality that works with the SSR of Next.js.