When building forms in React, you might need to create dependent dropdowns, where the options in one dropdown depend on the selection of another. This is commonly used in scenarios like selecting a category and then filtering relevant subcategories.
In this article, we’ll cover:
- How to create a dependent dropdown feature in React.
- How to filter options dynamically using an API.
- Handling empty states when no options are available.
1. Setting Up the React Component
Let’s start by setting up a simple form component with two dropdowns: Category and Subcategory.
import React, { useState, useEffect } from “react”;
const DependentDropdown = () => {
const [categories, setCategories] = useState([]);
const [subcategories, setSubcategories] = useState([]);
const [selectedCategory, setSelectedCategory] = useState(“”);
const [formData, setFormData] = useState({ subcategory_name: “”, subcategory_id: null });
useEffect(() => {
// Fetch categories from API on component mount
fetch(“https://api.example.com/categories”)
.then((response) => response.json())
.then((data) => setCategories(data))
.catch((error) => console.error(“Error fetching categories:”, error));
}, []);
useEffect(() => {
if (selectedCategory) {
// Fetch subcategories based on selected category
fetch(`https://api.example.com/subcategories?categoryId=${selectedCategory}`)
.then((response) => response.json())
.then((data) => setSubcategories(data))
.catch((error) => console.error(“Error fetching subcategories:”, error));
} else {
setSubcategories([]);
}
}, [selectedCategory]);
return (
<div>
{/* Category Dropdown */}
<div>
<label>Category:</label>
<select
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
>
<option value=””>Select Category</option>
{categories.map((category) => (
<option key={category.id} value={category.id}>
{category.name}
</option>
))}
</select>
</div>
{/* Subcategory Dropdown */}
<div>
<label>Subcategory:</label>
<select
value={formData.subcategory_name}
onChange={(e) => {
const selectedSubcategoryId = e.target.options[e.target.selectedIndex].dataset.id;
setFormData({
…formData,
subcategory_name: e.target.value,
subcategory_id: selectedSubcategoryId ? parseInt(selectedSubcategoryId) : 0,
});
}}
>
<option value=””>Select Subcategory</option>
{subcategories.length > 0 ? (
subcategories.map((subcategory) => (
<option key={subcategory.id} data-id={subcategory.id} value={subcategory.name}>
{subcategory.name}
</option>
))
) : (
<option disabled>No options available</option>
)}
</select>
</div>
</div>
);
};
export default DependentDropdown;
2. Explanation of the Code
Fetching Categories
- On component mount, the
useEffecthook fetches category data from the API and updates thecategoriesstate. - The category dropdown is populated with options from the API response.
Fetching and Filtering Subcategories
- When a category is selected, a second
useEffecthook fetches the corresponding subcategories from the API based on thecategoryId. - If no category is selected, the subcategories list is cleared.
Handling Empty State
- If the
subcategoriesarray is empty, we display a disabled<option>No options available</option>. - This ensures a better user experience by informing users when no data is available.
3. Benefits of This Approach
✅ Dynamic Filtering: Fetches only the necessary data when needed, reducing API calls.
✅ Scalability: Can be expanded to more dropdowns, like City → State → Country.
✅ Improved UX: Avoids showing irrelevant data and gracefully handles empty states.
This approach is useful in e-commerce platforms, admin dashboards, and any form where selection dependencies exist.