4 min read react
Dropdowns in React: Unveiling the Compound Component Pattern
Crafting an Advanced Dropdown in React: A Complete Guide Using the Compound Component Pattern
Let’s create an advanced dropdown menu in React, complete with keyboard navigation and accessibility features, using the Compound Component Pattern. This example will demonstrate how to build a cohesive and interactive dropdown component.
Step 1: Building the Dropdown Component
We begin by setting up the Dropdown
component with shared state and context.
import React, { useState, createContext, useContext } from "react";
const DropdownContext = createContext();
const Dropdown = ({ children, onSelect }) => {
const [isOpen, setIsOpen] = useState(false);
const [highlightedIndex, setHighlightedIndex] = useState(-1);
const [items, setItems] = useState(["Option 1", "Option 2", "Option 3"]);
const toggle = () => setIsOpen(!isOpen);
const close = () => setIsOpen(false);
const handleSelect = (item) => {
onSelect(item);
close();
};
const contextValue = {
isOpen,
toggle,
highlightedIndex,
setHighlightedIndex,
items,
handleSelect,
};
return (
<DropdownContext.Provider value={contextValue}>
<div className="dropdown">{children}</div>
</DropdownContext.Provider>
);
};
export default Dropdown;
Step 2: Implementing the Toggle Component
Create the Toggle
component to control the dropdown’s visibility.
Dropdown.Toggle = () => {
const { isOpen, toggle } = useContext(DropdownContext);
return (
<button onClick={toggle} aria-haspopup="true" aria-expanded={isOpen}>
Toggle Dropdown
</button>
);
};
Step 3: Creating the List and Item Components
Develop the List
and Item
components to display the dropdown options.
Dropdown.List = () => {
const { isOpen, highlightedIndex, items } = useContext(DropdownContext);
return isOpen ? (
<ul className="dropdown-list">
{items.map((item, index) => (
<Dropdown.Item
key={index}
item={item}
index={index}
isHighlighted={index === highlightedIndex}
/>
))}
</ul>
) : null;
};
Dropdown.Item = ({ item, index, isHighlighted }) => {
const { handleSelect } = useContext(DropdownContext);
return (
<li
className={`dropdown-item ${isHighlighted ? "highlighted" : ""}`}
onClick={() => handleSelect(item)}
>
{item}
</li>
);
};
Step 4: Adding Keyboard Navigation
Enhance the Dropdown
component to handle keyboard interactions.
// Inside Dropdown component, add the following methods:
const highlightNext = () => {
setHighlightedIndex((prev) => (prev < items.length - 1 ? prev + 1 : prev));
};
const highlightPrev = () => {
setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : prev));
};
const handleKeyDown = (e) => {
switch (e.key) {
case "ArrowDown":
e.preventDefault();
highlightNext();
break;
case "ArrowUp":
e.preventDefault();
highlightPrev();
break;
case "Enter":
e.preventDefault();
handleSelect(items[highlightedIndex]);
break;
case "Escape":
close();
break;
default:
break;
}
};
// Update the return statement to include onKeyDown handler
return (
<DropdownContext.Provider value={contextValue}>
<div className="dropdown" onKeyDown={handleKeyDown} tabIndex="0">
{children}
</div>
</DropdownContext.Provider>
);
Step 5: Integrating the Dropdown in an Application
Here’s the updated App component which includes the items for the dropdown:
const App = () => {
const handleSelect = (item) => {
console.log("Selected Item:", item);
};
return (
<Dropdown onSelect={handleSelect}>
<Dropdown.Toggle />
<Dropdown.List>
<Dropdown.Item item="Item 1">Item 1</Dropdown.Item>
<Dropdown.Item item="Item 2">Item 2</Dropdown.Item>
<Dropdown.Item item="Item 3">Item 3</Dropdown.Item>
</Dropdown.List>
</Dropdown>
);
};
export default App;
In this implementation, each Dropdown.Item is explicitly declared within the Dropdown.List. This ensures that the dropdown menu displays “Item 1”, “Item 2”, and “Item 3” as options, maintaining the structure and functionality of our advanced dropdown component.
Conclusion
This comprehensive example demonstrates building a feature-rich dropdown in React using the Compound Component Pattern. The dropdown component is not only interactive but also accessible, thanks to keyboard navigation. This pattern offers a scalable and maintainable approach to developing complex UI components.
Fun Fact: Did you know that dropdown menus in web design were initially inspired by similar concepts in desktop operating systems? They were one of the early UI elements that made the leap from desktop to web, adapting to the new environment like a chameleon!
Joke of the Day: Why did the JavaScript developer leave the restaurant? Because they couldn’t find the menu! 😄
Remember, in React just like in a good restaurant, a well-organized and accessible menu (or dropdown) can make a world of difference in user experience. Keep coding and keep smiling!