Day 11 of #100DaysOfMiva Coding Challenge
Creating intuitive and interactive user interfaces is a fundamental aspect of web development. Today, I worked on building a simple Tree View component using React. This component allows users to navigate through hierarchical data structures seamlessly.
In this article, I will break down the codebase step-by-step, explaining the concepts and technicalities involved. Whether you're a beginner or looking to reinforce your React skills, this walkthrough will guide you through creating your own Tree View component.
Table of Contents
- Introduction to Tree View
- Project Structure
- Setting Up the Data
- Creating the Tree View Components
- TreeView Component (index.jsx)
- MenuList Component (menu-list.jsx)
- MenuItem Component (menu-item.jsx)
- Styling the Components (styles.css)
- Putting It All Together
- Conclusion
- Possible Improvements
Introduction to Tree View
A Tree View is a graphical user interface component that displays a hierarchical list of items, allowing users to expand and collapse branches to reveal nested items. It's commonly used to represent file systems, organizational structures, and nested menus.
Key Features of a Tree View:
- Hierarchy Representation: Displays data in a parent-child relationship.
- Expand/Collapse Functionality: Allows users to view or hide nested items.
- Interactive Navigation: Users can traverse through different levels seamlessly.
Use Cases:
- File explorers (e.g., Windows Explorer)
- Navigation menus in websites and applications
- Organizational charts
- Category listings in e-commerce sites
Project Structure
Our project consists of the following files:
css
src/
│
├── data.js
├── index.jsx
├── menu-item.jsx
├── menu-list.jsx
└── styles.css
Description of Files:
data.js
: Contains the hierarchical data structure that will be displayed in the Tree View.
index.jsx
: The main component that initiates the Tree View rendering.
menu-list.jsx
: Responsible for rendering a list of menu items.
menu-item.jsx
: Handles individual menu items, including expand/collapse functionality.
styles.css
: Contains the styling for the Tree View components.
Setting Up the Data
We'll start by defining the hierarchical data structure that our Tree View will display.
data.js
// data.js
export const menus = [
{
label: "Home",
to: "/",
},
{
label: "Profile",
to: "/profile",
children: [
{
label: "Details",
to: "/profile/details",
children: [
{
label: "Location",
to: "/profile/details/location",
children: [
{
label: "City",
to: "/profile/details/location/city",
},
],
},
],
},
],
},
{
label: "Settings",
to: "/settings",
children: [
{
label: "Account",
to: "/settings/account",
},
{
label: "Security",
to: "/settings/security",
children: [
{
label: "Login",
to: "/settings/security/login",
},
{
label: "Register",
to: "/settings/security/register",
children: [
{
label: "Random Data",
to: "/settings/security/register/random-data",
},
],
},
],
},
],
},
];
export default menus;
Explanation:
- The
menus
array contains objects representing each menu item. - Each menu item has:
-
label
: The text displayed to the user. -
to
: The URL or path the menu item points to. -
children
: An optional array of sub-menu items, allowing for nested structures.
-
- This recursive structure allows us to represent complex hierarchies easily.
Example Structure Visualization:
- Home
- Profile
- Details
- Location
- City
- Settings
- Account
- Security
- Login
- Register
- Random Data
Creating the Tree View Components
Now, let's build the React components that will render this data as an interactive Tree View.
Prerequisites
Ensure you have a React application set up. You can create one using Create React App:
npx create-react-app tree-view-app
Install necessary dependencies:
npm install react-icons
We will use react-icons
for the expand and collapse icons.
TreeView Component (`index.jsx`)
This is the entry point of our Tree View component.
// index.jsx
import React from "react";
import MenuList from "./menu-list";
import menus from "./data";
import "./styles.css";
export default function TreeView() {
return (
<div className="tree-view-container">
<MenuList list={menus} />
</div>
);
}
Explanation:
- Imports:
-
React
: To use React functionalities. -
MenuList
: The component responsible for rendering a list of menu items. -
menus
: The data we defined earlier. -
styles.css
: The stylesheet for styling our components.
-
-
TreeView
Function:- Returns a
div
with the classtree-view-container
which wraps theMenuList
component. - Passes the
menus
data as a prop toMenuList
.
- Returns a
Purpose:
- Acts as a container and initiates the rendering process by supplying the initial data to
MenuList
.
MenuList Component (menu-list.jsx)
This component renders a list of menu items.
// menu-list.jsx
import React from "react";
import MenuItem from "./menu-item";
export default function MenuList({ list = [] }) {
return (
<ul className="menu-list-container">
{list.map((listItem, index) => (
<MenuItem key={index} item={listItem} />
))}
</ul>
);
}
Explanation:
- Imports:
-
React
: For React functionalities. -
MenuItem
: Component responsible for rendering individual menu items.
-
-
MenuList
Function:- Accepts a prop
list
, which is an array of menu items. - Returns an unordered list (
ul
) with the classmenu-list-container
. - Maps over the
list
array and renders aMenuItem
for each item. - Uses the index as a key for each
MenuItem
. In production, it's better to use a unique identifier.
- Accepts a prop
Purpose:
- Handles rendering a collection of menu items and delegates the rendering of each item to the
MenuItem
component. - Supports recursive rendering by allowing
MenuItem
components to render nestedMenuList
s.
MenuItem Component (menu-item.jsx)
This component renders individual menu items and handles expand/collapse functionality for items with children.
// menu-item.jsx
import React, { useState } from "react";
import MenuList from "./menu-list";
import { FaMinus, FaPlus } from "react-icons/fa";
export default function MenuItem({ item }) {
const [isExpanded, setIsExpanded] = useState(false);
const hasChildren = item.children && item.children.length > 0;
const handleToggle = () => {
setIsExpanded((prev) => !prev);
};
return (
<li>
<div className="menu-item">
<p>{item.label}</p>
{hasChildren && (
<span onClick={handleToggle} className="toggle-icon">
{isExpanded ? <FaMinus /> : <FaPlus />}
</span>
)}
</div>
{hasChildren && isExpanded && <MenuList list={item.children} />}
</li>
);
}
Explanation:
- Imports:
-
React
anduseState
: For React functionalities and managing component state. -
MenuList
: To render nested lists if the item has children. -
FaMinus
andFaPlus
: Icons fromreact-icons
for expand/collapse indicators.
-
-
MenuItem
Function:-
isExpanded
State: Manages whether the item's children are visible.- Initialized to
false
(collapsed). - Toggled by the
handleToggle
function.
- Initialized to
-
hasChildren
Variable:- Checks if the current item has children.
-
handleToggle
Function:- Toggles the
isExpanded
state betweentrue
andfalse
.
- Toggles the
- Rendering:
-
<li>
Element: Wraps each menu item. -
<div className="menu-item">
:- Contains the item's label and the toggle icon if the item has children.
-
<p>{item.label}</p>
: Displays the item's label. - Toggle Icon:
- Rendered only if the item has children.
- Clicking the icon calls
handleToggle
. - Displays
FaMinus
if expanded,FaPlus
if collapsed.
- Nested
MenuList
:- Rendered only if the item has children and
isExpanded
istrue
. - Passes
item.children
as the list prop to render nested items.
- Rendered only if the item has children and
-
-
Purpose:
- Display Menu Item: Shows the label and, if applicable, the expand/collapse icon.
- Manage Expand/Collapse State: Uses
useState
to control the visibility of child items. - Recursive Rendering: Supports nested structures by rendering
MenuList
within itself for child items.
Concepts Demonstrated:
- State Management: Using
useState
to manage UI state. - Conditional Rendering: Rendering elements based on conditions (e.g., whether an item has children, whether it's expanded).
- Event Handling: Toggling state in response to user interactions (click events).
- Recursion in Components: Rendering components within themselves to handle nested data structures.
Styling the Components (styles.css)
Proper styling enhances the user experience by making the interface intuitive and visually appealing.
/* styles.css */
.tree-view-container {
min-height: 100vh;
width: 300px;
background-color: #00476e;
padding: 20px;
color: #ffffff;
font-family: Arial, sans-serif;
}
.menu-list-container {
list-style: none;
padding-left: 20px;
margin: 5px 0;
}
.menu-item {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
padding: 5px 0;
}
.menu-item p {
margin: 0;
}
.toggle-icon {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
background-color: #0078a8;
border-radius: 50%;
color: #ffffff;
font-size: 14px;
}
.toggle-icon:hover {
background-color: #005f82;
}
Explanation:
-
.tree-view-container
:- Sets the height, width, background color, padding, text color, and font for the Tree View container.
-
.menu-list-container
:- Removes default list styling and adds indentation for nested lists.
-
.menu-item
:- Arranges the label and toggle icon horizontally.
- Adds spacing and cursor styling for better UX.
-
.menu-item p
:- Removes default margin for proper alignment.
-
.toggle-icon
:- Styles the expand/collapse icons with background color, size, and hover effects to make them easily identifiable and interactive.
Purpose:
- Provides a clean and consistent look to the Tree View component.
- Enhances usability by making interactive elements visually distinct.
- Maintains readability and organization across different levels of the hierarchy.
Putting It All Together
Now, let's see how all these components work together to render the Tree View.
App Entry Point (App.js)
:
// App.js
import React from "react";
import TreeView from "./TreeView";
function App() {
return (
<div className="App">
<TreeView />
</div>
);
}
export default App;
Directory Structure:
src/
│
├── data.js
├── TreeView/
│ ├── index.jsx
│ ├── menu-item.jsx
│ ├── menu-list.jsx
│ └── styles.css
└── App.js
Running the Application:
Start the Development Server:
npm start
View in Browser:
Navigate to http://localhost:3000/ to see the Tree View in action.
Interactive Features:
Expanding and Collapsing:
Click on the plus (+) icon to expand a menu item and reveal its children.
Click on the minus (-) icon to collapse and hide the children.
Nested Levels:
The component supports infinite nesting levels, as demonstrated by the deeply nested "City" and "Random Data" items.
Styling Consistency:
The styling ensures a consistent look and feel across all levels, with proper indentation and visual cues.
Conclusion
Building a Tree View component in React involves understanding and implementing several key concepts:
Recursive Components: Leveraging recursion to handle nested data structures elegantly.
State Management: Using React's useState
hook to manage UI state, such as the expand/collapse functionality.
Conditional Rendering: Rendering elements based on certain conditions, enhancing interactivity.
Modular Design: Breaking down the UI into reusable and maintainable components.
Styling: Applying consistent and responsive styles to improve user experience.
This project demonstrates how to construct a functional and interactive Tree View from scratch, providing a solid foundation for more complex implementations. Whether for navigation menus, file explorers, or organizational charts, understanding these principles enables developers to create versatile and dynamic interfaces.
Possible Improvements
While the current implementation serves as a solid starting point, there are several enhancements that can be made:
Routing Integration: Utilize React Router to navigate to different pages when clicking on menu items with the to property.
Dynamic Data Loading: Implement lazy loading for children, fetching data from an API when a parent item is expanded.
Accessibility Enhancements: Add keyboard navigation support and ARIA attributes for better accessibility.
Animation Effects: Incorporate smooth transition animations when expanding and collapsing menu items.
Search Functionality: Add a search bar to filter and highlight menu items dynamically.
Customization Options: Allow customization of styles and icons through props for greater flexibility.
Implementing these improvements would not only enrich the user experience but also make the component more robust and adaptable to various use cases.
Thank you for following along this walkthrough! I hope this explanation provides clarity and insight into building recursive, interactive components in React. Happy coding!
GitHub Repository: Day 11 of #100DaysOfMiva on GitHub
Feel free to check out the repository for the complete code and follow my progress throughout the #100DaysOfMiva coding challenge.