Build a Search Bar Component in React

A search bar looks simple until you add it to a real React dashboard. I have built them for sales activity screens, customer directories, ticket queues, and admin portals where users expect results to update as they type.

The key is to keep the search text in state, filter data without changing the original array, and render the matching results cleanly. This guide uses a sales activity dashboard example and gives you a reusable React search bar component.

What We Will Build

We will build a client-side React search bar that filters a sales activity list. The search works across a salesperson’s name, company, and activity type.

This is a practical React tutorial for modern React projects that use functional components and the useState hook. A functional component is a JavaScript function that returns UI. React uses JSX, a syntax that looks like HTML inside JavaScript, to describe that UI.

Our final dashboard will let a user type “Jessica,” “meeting,” or “Bluebird” and see only relevant records.

Sample output:

Sales Activity Dashboard

Search activities: [meeting ]

2 activities found

Jessica Miller — Client meeting — Bluebird Foods
David Carter — Client meeting — Northstar Retail

Before you start, make sure you have a working React project. If you need one, follow this guide to set up a ReactJS environment and create your first React app.

Build a Basic React Search Bar Component

A search bar needs two things:

  • An input field where the user enters text.
  • A value that React remembers and uses to filter records.

That remembered value is called state. State holds data that can change during a component’s lifetime. When state changes, React runs the component again and updates the browser view with the new result.

Create a file named SearchBar.jsx and add this code:

function SearchBar({ searchTerm, onSearchChange }) {
return (
<div className="search-bar">
<label htmlFor="activity-search">Search activities</label>

<input
id="activity-search"
type="search"
value={searchTerm}
onChange={(event) => onSearchChange(event.target.value)}
placeholder="Search by name, company, or activity"
/>
</div>
);
}

export default SearchBar;

This React component receives two props. Props are values that a parent component passes down to a child component.

  • searchTerm keeps the input controlled by React.
  • onSearchChange sends the latest typed text back to the parent.

The onChange attribute is an event handler. An event handler runs when a user action occurs. Here, it runs every time the user changes the search field.

Sample output:

Search activities

[ Search by name, company, or activity ]

I executed the above example code and added the screenshot below.

Search Bar Component in React

Using a controlled input gives React one reliable source for the displayed value. You can also learn more about controlled and uncontrolled React components when you work with larger forms.

Add Search State With useState

Now create the parent dashboard component. This component owns the list and the search state because it needs both values to create the filtered list.

The useState hook lets a functional component store changing values. It returns the current value and a function that updates it.

Create or replace App.jsx with the following complete code:

import { useState } from "react";
import SearchBar from "./SearchBar";

const activities = [
{
id: 1,
name: "Jessica Miller",
company: "Bluebird Foods",
activity: "Client meeting",
date: "June 12, 2026",
},
{
id: 2,
name: "David Carter",
company: "Northstar Retail",
activity: "Client meeting",
date: "June 11, 2026",
},
{
id: 3,
name: "Emily Johnson",
company: "Pinecrest Media",
activity: "Follow-up call",
date: "June 10, 2026",
},
{
id: 4,
name: "Michael Brown",
company: "Harbor Point Realty",
activity: "Proposal sent",
date: "June 9, 2026",
},
];

function App() {
const [searchTerm, setSearchTerm] = useState("");

const filteredActivities = activities.filter((activity) => {
const searchValue = searchTerm.toLowerCase();

return (
activity.name.toLowerCase().includes(searchValue) ||
activity.company.toLowerCase().includes(searchValue) ||
activity.activity.toLowerCase().includes(searchValue)
);
});

return (
<main className="dashboard">
<h1>Sales Activity Dashboard</h1>

<SearchBar
searchTerm={searchTerm}
onSearchChange={setSearchTerm}
/>

<p>{filteredActivities.length} activities found</p>

<ul>
{filteredActivities.map((activity) => (
<li key={activity.id}>
<strong>{activity.name}</strong> — {activity.activity} —{" "}
{activity.company} ({activity.date})
</li>
))}
</ul>
</main>
);
}

export default App;

This code stores the typed search value in searchTerm. Every keystroke calls setSearchTerm, which tells React to render the component again.

The filter() method creates a new array containing only matching items. Unlike reverse() or sort()filter() does not change the original array. That makes it a safe choice for filtering a React state array or static frontend data.

The map() method then turns each matching object into an <li> element. This is the standard way to render lists in React.

Sample output when the user searches for meeting:

Sales Activity Dashboard

Search activities
[ meeting ]

2 activities found

Jessica Miller — Client meeting — Bluebird Foods (June 12, 2026)
David Carter — Client meeting — Northstar Retail (June 11, 2026)

I executed the above example code and added the screenshot below.

Build Search Bar Component in React

Pro Tip: I always convert both the typed text and searchable fields to lowercase. Without that step, users may get different results for “jessica” and “Jessica,” which makes a search experience feel broken.

How the Search Bar Filters Data

The filter logic is the heart of this React search bar component:

const filteredActivities = activities.filter((activity) => {
const searchValue = searchTerm.toLowerCase();

return (
activity.name.toLowerCase().includes(searchValue) ||
activity.company.toLowerCase().includes(searchValue) ||
activity.activity.toLowerCase().includes(searchValue)
);
});

This code checks each activity object. The JavaScript includes() method returns true when text contains the search value.

For example, if a user types bluebird, React checks each name, company, and activity value. Only the activity with Bluebird Foods remains in filteredActivities.

Sample output when the user searches for bluebird:

1 activity found

Jessica Miller — Client meeting — Bluebird Foods (June 12, 2026)

This approach works well for local frontend applications, internal dashboards, simple admin portals, and smaller API-driven interfaces. For very large datasets, you should usually send the search term to an API instead of downloading and filtering thousands of records in the browser.

When you load data from an endpoint, keep the full response separate from the filtered result. This prevents accidental data loss and makes clearing the search easy. If your records come from an endpoint, this guide on fixing React API data that does not display in a component can help with common loading issues.

Add a No-Results Message

A polished search bar should tell users when no data matches. Otherwise, an empty area can look like a loading error.

Update the <ul> section in App.jsx with this code:

{filteredActivities.length > 0 ? (
<ul>
{filteredActivities.map((activity) => (
<li key={activity.id}>
<strong>{activity.name}</strong> — {activity.activity} —{" "}
{activity.company} ({activity.date})
</li>
))}
</ul>
) : (
<p>No activities match "{searchTerm}". Try another search.</p>
)}

This uses conditional rendering, which means React displays different JSX based on a condition. The condition checks whether filteredActivities contains at least one item.

Sample output when the user searches for invoice:

0 activities found

No activities match "invoice". Try another search.

I executed the above example code and added the screenshot below.

Build a Search Bar Component in React

I use this pattern in support portals and account dashboards because it gives users immediate feedback. They know the search completed, even though it found no records.

Make the Search Bar Reusable

A reusable component should not depend on one specific dashboard. The current SearchBar component already accepts its value and update function through props, so you can use it for customer lists, product catalogs, tickets, or employee directories.

Here is a more flexible version that also accepts a label and placeholder:

function SearchBar({
label = "Search",
placeholder = "Type to search",
searchTerm,
onSearchChange,
}) {
return (
<div className="search-bar">
<label htmlFor="search-input">{label}</label>

<input
id="search-input"
type="search"
value={searchTerm}
onChange={(event) => onSearchChange(event.target.value)}
placeholder={placeholder}
/>
</div>
);
}

export default SearchBar;

You can now use the same component in the sales dashboard like this:

<SearchBar
label="Search sales activities"
placeholder="Search by name, company, or activity"
searchTerm={searchTerm}
onSearchChange={setSearchTerm}
/>

The parent owns the data and state, while the child component handles the input UI. This separation makes components easier to test, reuse, and maintain. It also follows a practical React container component pattern where the parent manages data and the child focuses on presentation.

Sample output:

Search sales activities

[ Search by name, company, or activity ]

Pro Tip: I avoid placing the full filtering logic inside a basic search input component. Keeping it in the parent makes the search bar reusable and stops one component from knowing too much about unrelated data structures.

Add Simple Styling

You can add basic CSS to make the search bar easier to use in a real dashboard. Create or update App.css with this complete code:

* {
box-sizing: border-box;
}

body {
margin: 0;
background: #f4f7fb;
color: #1f2937;
font-family: Arial, sans-serif;
}

.dashboard {
max-width: 760px;
margin: 48px auto;
padding: 32px;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 8px 24px rgba(31, 41, 55, 0.1);
}

.search-bar {
display: grid;
gap: 8px;
margin: 24px 0 16px;
}

.search-bar label {
font-weight: 700;
}

.search-bar input {
width: 100%;
padding: 12px 14px;
border: 1px solid #cbd5e1;
border-radius: 6px;
font-size: 16px;
}

.search-bar input:focus {
border-color: #2563eb;
outline: 3px solid rgba(37, 99, 235, 0.18);
}

ul {
padding-left: 20px;
}

li {
margin: 12px 0;
}

This CSS gives the input a visible label, a larger clickable area, and a focus style. The focus style matters because keyboard users need to see where they are on the page.

Import the stylesheet in App.jsx:

import "./App.css";

Sample output:

A centered white sales dashboard card on a light gray page.

Search sales activities
[ Search by name, company, or activity ]

Matching activity records appear below the search bar.

Things to Keep in Mind

  • Keep the original array unchanged: Use filter() to create a derived list instead of overwriting the source data.
  • Use controlled inputs: Connect the input value to state so React always controls what the user sees.
  • Normalize text before comparing: Convert both values to lowercase to deliver case-insensitive results.
  • Use stable keys: Use an item ID such as activity.id when you render lists in React. Avoid array indexes if records can change order.
  • Do not store derived data unnecessarily: Keep the source array and search term in state when needed, then calculate filtered results during rendering.
  • Move large searches to the server: Client-side filtering works well for small local lists, but API-driven interfaces should use server-side search for large datasets.

Frequently Asked Questions

How do I create a search bar component in React?

Create an input component that accepts a value and an onChange callback through props. Store the typed value with the useState hook in the parent component. Filter the parent’s data array using the search term.

Should I use useState for a React search bar?

Yes, use useState when the search text changes as users type. React needs that state value to trigger a re-render and update the matching results. You can keep the input value and filtered result in sync through the same state.

How do I filter an array in React?

Use JavaScript’s filter() method to return a new array of matching records. Perform the filter inside your component using the current search value. Then use map() to render the returned array.

Why is my React search not case-insensitive?

Your code likely compares text with different capitalization. Convert the input and each searchable value with toLowerCase() before calling includes(). This makes DAVIDDavid, and david return the same result.

Can I search more than one property in a React list?

Yes. Add multiple checks inside the filter() callback and join them with the || operator. The sales activity example searches the name, company, and activity type fields.

Should I filter API data in React or on the server?

Filter small datasets in React when the browser already has all records. Use server-side filtering when the dataset is large, sensitive, paginated, or frequently updated. Server-side search also avoids sending unnecessary records to the browser.

A React search bar component becomes reliable when you store the typed value in state, derive filtered results with filter(), and render each result with stable keys. Keep the input component focused on user interaction and let the parent component own the data logic.

You May Also Like

Leave a Comment

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.