Create a simple Google search bar component with React πŸ•΅πŸ»β€

Published: August 4, 2024

We'll create a Google-style search bar component in React in about 7 minutes.

Here's how the final result will look:

And here's a video walkthrough (featuring me):

Step 1: Set Up Your React Environment

  1. Ensure you have Node.js installed on your system.
node -v

If you don't have Node.js installed, download and install it: https://nodejs.org/en/download/

  1. Create a new React project using Vite:
npm create vite@latest google-search-bar
cd google-search-bar

Then select React > JavaScript.

  1. Install our packages:
npm install
npm install lucide-react

We use the lucide-react package for icons.

Step 2: Create the GoogleSearchBar Component

Create a new file called GoogleSearchBar.jsx in your google-search-bar/src and add the following code:

import React from 'react'
import { Search, Mic } from 'lucide-react'

const GoogleSearchBar = () => {
  // Component code will go here
}

export default GoogleSearchBar

Step 3: Add Sample Data

Update GoogleSearchBar.jsx to include our sample data:

import React from 'react'
import { Search, Mic } from 'lucide-react'

const sampleData = [
  {
    id: 1,
    title: 'React Official Documentation',
    url: 'https://reactjs.org/',
  },
  {
    id: 2,
    title: 'Mozilla Developer Network (MDN)',
    url: 'https://developer.mozilla.org/',
  },
  {
    id: 3,
    title: 'Stack Overflow',
    url: 'https://stackoverflow.com/',
  },
  {
    id: 4,
    title: 'GitHub',
    url: 'https://github.com/',
  },
  {
    id: 5,
    title: 'npm',
    url: 'https://www.npmjs.com/',
  },
]

const GoogleSearchBar = () => {
  // Component code will go here
}

export default GoogleSearchBar

Step 4: Implement the Search State and Results

Update GoogleSearchBar.jsx to include state and the debounce function. We use a debouncer to trigger the search after a short delay when the user stops typing, rather than on every keystroke.

import React, { useState, useCallback, useEffect } from 'react'
import { Search, Mic } from 'lucide-react'

const sampleData = [
  {
    id: 1,
    title: 'React Official Documentation',
    url: 'https://reactjs.org/',
  },
  {
    id: 2,
    title: 'Mozilla Developer Network (MDN)',
    url: 'https://developer.mozilla.org/',
  },
  {
    id: 3,
    title: 'Stack Overflow',
    url: 'https://stackoverflow.com/',
  },
  {
    id: 4,
    title: 'GitHub',
    url: 'https://github.com/',
  },
  {
    id: 5,
    title: 'npm',
    url: 'https://www.npmjs.com/',
  },
]

const GoogleSearchBar = () => {
  // Todo for you: Add the below code to the GoogleSearchBar component:
  const [searchTerm, setSearchTerm] = useState('')
  const [searchResults, setSearchResults] = useState([])

  const debounce = (func, delay) => {
    let timeoutId
    return (...args) => {
      clearTimeout(timeoutId)
      timeoutId = setTimeout(() => func(...args), delay)
    }
  }

  // More code will be added here
}

export default GoogleSearchBar

Step 5: Create the Search Handler

Add the search handler to GoogleSearchBar.jsx :

import React, { useState, useCallback, useEffect } from 'react'
import { Search, Mic } from 'lucide-react'

const sampleData = [
  {
    id: 1,
    title: 'React Official Documentation',
    url: 'https://reactjs.org/',
  },
  {
    id: 2,
    title: 'Mozilla Developer Network (MDN)',
    url: 'https://developer.mozilla.org/',
  },
  {
    id: 3,
    title: 'Stack Overflow',
    url: 'https://stackoverflow.com/',
  },
  {
    id: 4,
    title: 'GitHub',
    url: 'https://github.com/',
  },
  {
    id: 5,
    title: 'npm',
    url: 'https://www.npmjs.com/',
  },
]

const GoogleSearchBar = () => {
  const [searchTerm, setSearchTerm] = useState('')
  const [searchResults, setSearchResults] = useState([])

  const debounce = (func, delay) => {
    let timeoutId
    return (...args) => {
      clearTimeout(timeoutId)
      timeoutId = setTimeout(() => func(...args), delay)
    }
  }

  // Todo for you: Add the below code to the GoogleSearchBar component:
  const handleSearch = useCallback(
    debounce((term) => {
      if (term.trim() === '') {
        setSearchResults([])
      } else {
        const results = sampleData.filter((item) =>
          item.title.toLowerCase().includes(term.toLowerCase()),
        )
        setSearchResults(results)
      }
    }, 300),
    [],
  )

  useEffect(() => {
    handleSearch(searchTerm)
  }, [searchTerm, handleSearch])

  const handleInputChange = (e) => {
    setSearchTerm(e.target.value)
  }

  // JSX will be added here
}

export default GoogleSearchBar

Step 6: Build the Component JSX

Complete the GoogleSearchBar.jsx component by adding the JSX:

import React, { useState, useCallback, useEffect } from 'react'
import { Search, Mic } from 'lucide-react'

const sampleData = [
  {
    id: 1,
    title: 'React Official Documentation',
    url: 'https://reactjs.org/',
  },
  {
    id: 2,
    title: 'Mozilla Developer Network (MDN)',
    url: 'https://developer.mozilla.org/',
  },
  {
    id: 3,
    title: 'Stack Overflow',
    url: 'https://stackoverflow.com/',
  },
  {
    id: 4,
    title: 'GitHub',
    url: 'https://github.com/',
  },
  {
    id: 5,
    title: 'npm',
    url: 'https://www.npmjs.com/',
  },
]

const GoogleSearchBar = () => {
  const [searchTerm, setSearchTerm] = useState('')
  const [searchResults, setSearchResults] = useState([])

  const debounce = (func, delay) => {
    let timeoutId
    return (...args) => {
      clearTimeout(timeoutId)
      timeoutId = setTimeout(() => func(...args), delay)
    }
  }

  const handleSearch = useCallback(
    debounce((term) => {
      if (term.trim() === '') {
        setSearchResults([])
      } else {
        const results = sampleData.filter((item) =>
          item.title.toLowerCase().includes(term.toLowerCase()),
        )
        setSearchResults(results)
      }
    }, 300),
    [],
  )

  useEffect(() => {
    handleSearch(searchTerm)
  }, [searchTerm, handleSearch])

  const handleInputChange = (e) => {
    setSearchTerm(e.target.value)
  }

  // Todo for you: Add the below code to the GoogleSearchBar component:
  return (
    <div className="flex min-h-screen flex-col items-center bg-white p-4">
      <form
        onSubmit={(e) => e.preventDefault()}
        className="mb-8 w-full max-w-2xl"
      >
        <div className="relative">
          <input
            type="text"
            value={searchTerm}
            onChange={handleInputChange}
            className="w-full rounded-full border border-gray-200 bg-white px-5 py-3 pr-20 text-base shadow-md transition-shadow duration-200 hover:shadow-lg focus:border-gray-300 focus:outline-none"
            placeholder="Search Google or type a URL"
          />
          <div className="absolute right-0 top-0 mr-4 mt-3 flex items-center">
            <button
              type="button"
              className="mr-3 text-gray-400 hover:text-gray-600"
              onClick={() =>
                alert(
                  'Voice search is unsupported in this demo.\nTry implementing this feature yourself πŸ™‚',
                )
              }
            >
              <Mic size={20} />{' '}
            </button>{' '}
            <button type="submit" className="text-blue-500 hover:text-blue-600">
              <Search size={20} />{' '}
            </button>{' '}
          </div>{' '}
        </div>{' '}
      </form>{' '}
      {searchResults.length > 0 && (
        <div className="w-full max-w-2xl rounded-lg bg-white p-4 shadow-md">
          <h2 className="mb-4 text-xl font-bold"> Search Results: </h2>{' '}
          <ul>
            {' '}
            {searchResults.map((result) => (
              <li key={result.id} className="mb-2">
                <a
                  href={result.url}
                  className="text-blue-600 hover:underline"
                  target="_blank"
                  rel="noopener noreferrer"
                >
                  {' '}
                  {result.title}{' '}
                </a>{' '}
              </li>
            ))}{' '}
          </ul>{' '}
        </div>
      )}{' '}
    </div>
  )
}

export default GoogleSearchBar

Step 7: Add Tailwind CSS for styling

  1. Install Tailwind CSS: In your google-search-bar directory, run:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

You should now have a tailwind.config.js file in your project root.

Note: Ensure that you're in the google-search-bar directory when you run these commands. Otherwise tailwind will be installed in the wrong directory, and it won't style your components.

  1. Configure your tailwind.config.js: Paste the following code into your tailwind.config.js file:
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
}
  1. Add Tailwind directives to your CSS: In your src/index.css file, replace the existing code with the following:
@tailwind base;
@tailwind components;
@tailwind utilities;

Step 8: Use the Component

Update your App.jsx (in google-search-bar/src ) to use the GoogleSearchBar component. Paste the following code:

import React from 'react'
import GoogleSearchBar from './GoogleSearchBar'

function App() {
  return (
    <div className="App">
      <GoogleSearchBar />
    </div>
  )
}

export default App

Step 9: Run Your Application

  1. Start your React application:
npm run dev
  1. Open your browser and navigate to http://localhost:5173 to see your Google-style search bar in action!

Congratulations! You've created a Google-style search bar in React with sample data.

Next steps:

  • Connect your search bar to a real API. It would be fun to connect this to the Bing search API directly, or your custom backend, perhaps using Django Ninja

Subscribe to my free newsletter

Get updates on AI, software, and business.