Create a simple Google search bar component with React 🕵🏻‍

Photo of Tom Dekan
by Tom Dekan

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 flex-col items-center min-h-screen bg-white p-4">
              <form onSubmit={(e) => e.preventDefault()} className="w-full max-w-2xl mb-8">
                 <div className="relative">
                    <input
                            type="text"
                            value={searchTerm}
                            onChange={handleInputChange}
                            className="w-full px-5 py-3 pr-20 text-base bg-white border border-gray-200 rounded-full focus:outline-none focus:border-gray-300 shadow-md hover:shadow-lg transition-shadow duration-200"
                            placeholder="Search Google or type a URL"
                    />
                    <div className="absolute right-0 top-0 mt-3 mr-4 flex items-center">
                       <button
                               type="button"
                               className="text-gray-400 hover:text-gray-600 mr-3"
                               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 bg-white rounded-lg shadow-md p-4">
                         <h2 className="text-xl font-bold mb-4">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

Let's get visual.

Do you want to create beautiful frontends effortlessly?
Click below to book your spot on our early access mailing list (as well as early adopter prices).
Copied link to clipboard 📋

Made with care by Tom Dekan

© 2024 Photon Designer