fervor [>]CODING & CURIOSITY
FERVOR LEARNING SYSTEMTUTORIALS
← React

React / 10 MIN READ

Search Bar

Searching all Day, all night

From the original Fervor library. Examples may use older package versions.

Oh yeahh! We are going to create a search bar in a React app that searches through the titles of items in a JSON file:

  • This is how we are doing it.
  • Create a new functional component for the search bar
  • Create a useState hook to manage the search input and search results
  • Add an event handler to handle search input changes
  • Import and use the component in your main app
  • Add a JSON file with sample data

Create a new functional component for the search bar, SearchBar.js:

We are going to break it down so you know whats happening in the code. if you are impatient feel free to scroll for full code. It is always good to know what is going on though.

  1. Import required dependencies and data:
   import React, { useState } from 'react';
   import data from './data.json';
   import './SearchBar.css';

Import the React library, useState hook, data from the JSON file, and the CSS styles for the SearchBar component.

  1. Create the SearchBar component:
   const SearchBar = () => {
     ...
   };

Define a functional component called SearchBar.

  1. Initialize state variables:
   const [search, setSearch] = useState('');
   const [results, setResults] = useState([]);

Initialize two state variables using useState - ‘search’ for storing the user’s search input, and ‘results’ for storing the filtered search results.

  1. Define the handleSearch function:
   const handleSearch = (e) => {
     ...
   };

Create a function called handleSearch that will be called when the user types into the search input.

  1. Update the search state:
   setSearch(e.target.value);

Set the value of the search state to the current value of the input field.

  1. Filter data based on user input:
   const filteredData = data.filter((item) =>
     item.title.toLowerCase().includes(e.target.value.toLowerCase())
   );

Filter the imported data by checking if the title of each item includes the search input (case-insensitive).

  1. Update the results state:
   setResults(filteredData);

Set the value of the results state to the filtered data.

  1. Return the JSX structure:
   return (
     ...
   );

Render the JSX structure for the search bar component, which includes the input field and the div element for displaying the search results.

  1. Create the search input:
   <input
     type="text"
     value={search}
     onChange={handleSearch}
     placeholder="Search titles..."
     className="search-input"
   />

Create an input element with the type “text”, the value set to the search state, an onChange event handler that calls the handleSearch function, a placeholder, and a className for styling.

  1. Display search results:
   <div className="search-results">
     {results.map((result) => (
       ...
     ))}
   </div>

Create a div element with a className for styling. Map over the results state and display each result.

  1. Render search result:
   <div key={result.id} className="search-result">
     <h3>{result.title}</h3>
     <p>{result.description}</p>
   </div>

For each search result, render a div element with a key set to the result’s id, a className for styling, and display the result’s title and description.

  1. Export the SearchBar component:
   export default SearchBar;

Export the SearchBar component as the default export, allowing it to be imported and used in other components.

Full Code for You

   import React, { useState } from 'react';
   import data from './data.json';
   import './SearchBar.css';

   const SearchBar = () => {
     const [search, setSearch] = useState('');
     const [results, setResults] = useState([]);

     const handleSearch = (e) => {
       setSearch(e.target.value);
       const filteredData = data.filter((item) =>
         item.title.toLowerCase().includes(e.target.value.toLowerCase())
       );
       setResults(filteredData);
     };

     return (
       <div>
         <input
           type="text"
           value={search}
           onChange={handleSearch}
           placeholder="Search titles..."
           className="search-input"
         />
         <div className="search-results">
           {results.map((result) => (
             <div key={result.id} className="search-result">
               <h3>{result.title}</h3>
               <p>{result.description}</p>
             </div>
           ))}
         </div>
       </div>
     );
   };

   export default SearchBar;

Create a CSS file, SearchBar.css, to style the search bar and search results:

   .search-input {
     width: 100%;
     padding: 6px 10px;
     font-size: 14px;
     border: 1px solid #ccc;
     border-radius: 3px;
   }

   .search-results {
     margin-top: 10px;
   }

   .search-result {
     background-color: #fff;
     border: 1px solid #ccc;
     border-radius: 5px;
     padding: 15px;
     margin-bottom: 10px;
   }

Add a JSON file with sample data, data.json:

   [
     {
       "id": 1,
       "title": "Sample Title 1",
       "description": "Sample description for title 1."
     },
     {
       "id": 2,
       "title": "Sample Title 2",
       "description": "Sample description for title 2."
     },
     {
       "id": 3,
       "title": "Sample Title 3",
       "description": "Sample description for title 3."
     }
   ]

Import and use the SearchBar component in your main app, for example, in App.js:

   import React from 'react';
   import SearchBar from './SearchBar';

   const App = () => {
     return (
       <div>
         <header>
           {/* Your header content */}
         </header>
         <main>
           <SearchBar />
           {/* Your main app content */}
         </main>
       </div>
     );
   };

   export default App;

If you want to go over the top and add an Auto-complete feature it time for some

BONUS TIME

example of how to add an auto-complete feature to the search bar in a React app:

  • Update the functional component for the search bar
  • Create a useState hook to manage the auto-complete suggestions
  • Add an event handler to handle search input changes and generate suggestions
  • Update the component’s JSX to display suggestions
  • Update the CSS file to style the auto-complete suggestions
  1. Update the functional component for the search bar, SearchBar.js:
   import React, { useState } from 'react';
   import data from './data.json';
   import './SearchBar.css';

   const SearchBar = () => {
     const [search, setSearch] = useState('');
     const [results, setResults] = useState([]);
     const [suggestions, setSuggestions] = useState([]);

     const handleSearch = (e) => {
       setSearch(e.target.value);

       const filteredData = data.filter((item) =>
         item.title.toLowerCase().includes(e.target.value.toLowerCase())
       );
       setResults(filteredData);

       if (e.target.value !== '') {
         const autoCompleteSuggestions = data
           .filter((item) =>
             item.title.toLowerCase().startsWith(e.target.value.toLowerCase())
           )
           .slice(0, 5);
         setSuggestions(autoCompleteSuggestions);
       } else {
         setSuggestions([]);
       }
     };

     const handleSuggestionClick = (suggestion) => {
       setSearch(suggestion.title);
       setResults([suggestion]);
       setSuggestions([]);
     };

     return (
       <div>
         <input
           type="text"
           value={search}
           onChange={handleSearch}
           placeholder="Search titles..."
           className="search-input"
         />
         <div className="suggestions">
           {suggestions.map((suggestion) => (
             <div
               key={suggestion.id}
               onClick={() => handleSuggestionClick(suggestion)}
               className="suggestion"
             >
               {suggestion.title}
             </div>
           ))}
         </div>
         <div className="search-results">
           {results.map((result) => (
             <div key={result.id} className="search-result">
               <h3>{result.title}</h3>
               <p>{result.description}</p>
             </div>
           ))}
         </div>
       </div>
     );
   };

   export default SearchBar;
  1. Update the CSS file, SearchBar.css, to style the auto-complete suggestions:
   .search-input {
     width: 100%;
     padding: 6px 10px;
     font-size: 14px;
     border: 1px solid #ccc;
     border-radius: 3px;
   }

   .suggestions {
     position: absolute;
     background-color: #fff;
     box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
     border: 1px solid #ccc;
     border-radius: 3px;
     width: 100%;
     z-index: 2;
     display: flex;
     flex-direction: column;
   }

   .suggestion {
     padding: 8px 10px;
     cursor: pointer;
   }

   .suggestion:hover {
     background-color: #f1f1f1;
   }

   .search-results {
     margin-top: 10px;
   }

   .search-result {
     background-color: #fff;
     border: 1px solid #ccc;
     border-radius: 5px;
     padding: 15px;
     margin-bottom: 10px;
   }

lets look at it in depth so we can get a better understanding of what just happened.

Second Look

  1. Update the useState hook to manage auto-complete suggestions:

    Add a new useState hook for suggestions:

   const [suggestions, setSuggestions] = useState([]);

This hook will be used to store and manage the auto-complete suggestions.

  1. Add an event handler to handle search input changes and generate suggestions:

    Update the handleSearch function to generate auto-complete suggestions based on the input:

   const handleSearch = (e) => {
     setSearch(e.target.value);

     const filteredData = data.filter((item) =>
       item.title.toLowerCase().includes(e.target.value.toLowerCase())
     );
     setResults(filteredData);

     if (e.target.value !== '') {
       const autoCompleteSuggestions = data
         .filter((item) =>
           item.title.toLowerCase().startsWith(e.target.value.toLowerCase())
         )
         .slice(0, 5);
       setSuggestions(autoCompleteSuggestions);
     } else {
       setSuggestions([]);
     }
   };

When the user types in the search bar, the function generates auto-complete suggestions based on the search input. The function filters the data and shows up to 5 suggestions that start with the entered text.

Add another function to handle suggestion clicks:

   const handleSuggestionClick = (suggestion) => {
     setSearch(suggestion.title);
     setResults([suggestion]);
     setSuggestions([]);
   };

This function updates the search input with the clicked suggestion’s title, displays the suggestion as a search result, and clears the suggestions list.

  1. Update the component’s JSX to display suggestions:

    Add a new div element to display the auto-complete suggestions:

   <div className="suggestions">
     {suggestions.map((suggestion) => (
       <div
         key={suggestion.id}
         onClick={() => handleSuggestionClick(suggestion)}
         className="suggestion"
       >
         {suggestion.title}
       </div>
     ))}
   </div>

This div element maps over the suggestions array and creates a new div element for each suggestion. When a suggestion is clicked, the handleSuggestionClick function is called with the selected suggestion.

  1. Add a new CSS class to style the auto-complete suggestions:

    Add the following CSS classes to SearchBar.css to style the auto-complete suggestions:

   .suggestions {
     position: absolute;
     background-color: #fff;
     box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
     border: 1px solid #ccc;
     border-radius: 3px;
     width: 100%;
     z-index: 2;
     display: flex;
     flex-direction: column;
   }

   .suggestion {
     padding: 8px 10px;
     cursor: pointer;
   }

   .suggestion:hover {
     background-color: #f1f1f1;
   }

The .suggestions class sets the position, background color, box-shadow, border, and dimensions of the suggestions container. The .suggestion class sets the padding and cursor for each suggestion, and the .suggestion:hover class sets the background color when the user hovers over a suggestion.

Bonu OverTime

Another One for you!!

To reuse the search bar in multiple pages and search across multiple JSON files, you can make the following modifications:

Pass the data source(s) as a prop to the SearchBar component.

Update the handleSearch function to filter data from multiple JSON files.

  1. Modify the SearchBar component to accept a prop called ‘dataSources’:
   const SearchBar = ({ dataSources }) => {
     ...
   };
  1. Update the handleSearch function to filter data from multiple JSON files:
   const handleSearch = (e) => {
     setSearch(e.target.value);

     const filteredData = dataSources
       .flatMap((source) => source.data)
       .filter((item) =>
         item.title.toLowerCase().includes(e.target.value.toLowerCase())
       );
     setResults(filteredData);
   };

The handleSearch function now filters data from all data sources provided through the dataSources prop. The flatMap function is used to merge the data arrays from all sources into a single array, which is then filtered based on the search input.

  1. Import the required JSON files in the parent component:
   import data1 from './data1.json';
   import data2 from './data2.json';
   import data3 from './data3.json';

Import the JSON files you want to search across in the parent component where you will use the SearchBar.

  1. Use the SearchBar component and pass the dataSources prop:
   <SearchBar dataSources={[{ data: data1 }, { data: data2 }, { data: data3 }]} />

Use the SearchBar component in the parent component and pass an array of data sources as a prop. Each data source should have a ‘data’ property containing the JSON data.

Fetching Data in the parent

You might want to fetch the data in the parent… who knows maybe you want to transition to a database later… Here it is!

  1. Import the required dependencies in the parent component:
   import React, { useState, useEffect } from 'react';

Import the React library along with useState and useEffect hooks in the parent component.

  1. Initialize a state variable to store the fetched data:
   const [fetchedData, setFetchedData] = useState([]);

Initialize a state variable called ‘fetchedData’ and a corresponding setter function ‘setFetchedData’ using the useState hook. Set the initial value to an empty array.

  1. Fetch the data in the parent component using useEffect:
   useEffect(() => {
     const fetchData = async () => {
       try {
         const response1 = await fetch('/data1.json');
         const data1 = await response1.json();
         const response2 = await fetch('/data2.json');
         const data2 = await response2.json();
         // Add more fetch calls for additional JSON files if needed

         setFetchedData([...data1, ...data2]);
       } catch (error) {
         console.error('Error fetching data:', error);
       }
     };

     fetchData();
   }, []);

Use the useEffect hook to fetch the data from multiple JSON files when the component mounts. Create an async function called ‘fetchData’ that fetches data from the required JSON files using the fetch API. After fetching the data, use the setFetchedData function to update the ‘fetchedData’ state with the combined data from all JSON files.

  1. Pass the fetched data to the SearchBar component:
   <SearchBar dataSources={[{ data: fetchedData }]} />

Use the SearchBar component in the parent component and pass the fetched data as a prop. The data is provided as an array of data sources with a ‘data’ property containing the combined fetched data.

Keep your curiosity going.Explore more React →
287 TUTORIALS · 22 TOPICSREADY