🔍 Implement Search & Category Filtering in React with TailwindCSS (2025 Guide)
In this guide, you’ll learn how to implement powerful search and category filtering in a React application using TailwindCSS for styling. This builds on a previous project where we created a responsive recipe website.
By the end of this tutorial, you'll be able to:
Filter recipe cards by text input
Filter by category dropdown
Clear search with a single click
Ensure case-insensitive matching
✅ Prerequisites
A React app already set up (ideally with TailwindCSS + recipe data)
Basic understanding of React state and hooks
🧱 Step 1: Create State for Search and Category
Inside your RecipesPage.jsx
(or App.jsx
if everything is in one file):
const [searchQuery, setSearchQuery] = useState("");
const [category, setCategory] = useState("");
const [filteredRecipes, setFilteredRecipes] = useState(recipes);
🎨 Step 2: Create the UI
🔍 Search + Filter Inputs
<div className="container mx-auto mt-8">
<h2 className="text-3xl font-bold mb-8 text-center text-gray-800">Featured Recipes</h2>
<div className="flex flex-col md:flex-row justify-center mb-6 space-y-4 md:space-y-0 md:space-x-4">
<input
type="text"
placeholder="Search for recipes..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full md:w-1/2 px-4 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-amber-500"
/>
<select
value={category}
onChange={(e) => setCategory(e.target.value)}
className="w-full md:w-1/4 px-4 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-amber-500"
>
<option>All Categories</option>
{[...new Set(recipes.map(recipe => recipe.category))].map((cat, i) => (
<option key={i} value={cat}>{cat}</option>
))}
</select>
<button
onClick={() => {
setSearchQuery("");
setCategory("");
}}
className="cursor-pointer bg-gradient-to-r from-amber-500 to-orange-500 hover:from-orange-500 hover:to-amber-500 text-white px-6 py-2 rounded transition duration-300"
>
Clear Search
</button>
</div>
</div>
⚙️ Step 3: Search Logic with useEffect
useEffect(() => {
const query = searchQuery.toLowerCase();
const result = recipes.filter(recipe =>
recipe.title.toLowerCase().includes(query) ||
recipe.ingredients.some(ing => ing.toLowerCase().includes(query)) ||
recipe.category.toLowerCase().includes(query)
);
if (category) {
setFilteredRecipes(result.filter(recipe => recipe.category === category));
} else {
setFilteredRecipes(result);
}
}, [searchQuery, category]);
This runs every time the search query or category changes.
📦 Step 4: Display Filtered Recipes
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredRecipes.length > 0 ? (
filteredRecipes.map((recipe, i) => (
<RecipeCard key={i} recipe={recipe} />
))
) : (
<p className="text-center col-span-full">No recipes found.</p>
)}
</div>
🧠 Bonus: Tips
Use
toLowerCase()
to make searching case-insensitiveUse
Set
to generate unique categoriesAdd debounce if your search data is large
For UX, make the clear button instantly reset filters
📈 SEO Keywords
React search filter tutorial 2025
Tailwind CSS form input search
Recipe search filter React example
Case-insensitive search with useEffect
Responsive dropdown in React + TailwindCSS
Share this post