Building a Project List Component with Filtering and Modal Details in React
In this tutorial, we will build a simple project list component using React and Fluent UI. This component will allow users to:
- View a list of projects.
- Filter the projects by name.
- Click on a project to view its details in a modal dialog.
We’ll use Fluent UI components, including DetailsList for the project list, TextField for filtering, and Modal for displaying project details.
Prerequisites
To follow along, make sure you have:
- React installed.
- Fluent UI installed: You can install Fluent UI using
npm install @fluentui/react.
Step 1: Setting Up the Project Component
To start, we’ll define a basic component structure. Inside this component, we’ll define the project data structure and initial project data. We’ll also set up state management for modal visibility, project selection, and filtering.
import * as React from 'react';
import { useBoolean } from '@fluentui/react-hooks';
import { Modal, DetailsList, IColumn, TextField } from '@fluentui/react';
// Define the project type
interface Project {
id: number;
name: string;
description: string;
}
// Sample project data
const initialProjects: Project[] = [
{ id: 1, name: "Project A", description: "Description for Project A" },
{ id: 2, name: "Project B", description: "Description for Project B" },
{ id: 3, name: "Project C", description: "Description for Project C" },
];
Here, Project defines the structure of each project. The initialProjects array serves as our sample data for this component.
Step 2: Implementing the ProjectList Component
We’ll now build the main component, ProjectList, which will render the project list, filter input, and modal for displaying details.
- State Management: We use
useBooleanto manage the modal’s open/close state anduseStatefor selected projects and filter text. - Column Definition: Define columns for
DetailsList. - Event Handlers: Set up handlers for filtering and modal actions.
const ProjectList: React.FunctionComponent = () => {
const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false);
const [selectedProject, setSelectedProject] = React.useState<Project | null>(null);
const [filterText, setFilterText] = React.useState<string>('');
// Reference initial projects as constant
const projects: Project[] = initialProjects;
// Define columns for the DetailsList
const columns: IColumn[] = [
{
key: 'column1',
name: 'Project Name',
fieldName: 'name',
minWidth: 100,
maxWidth: 300,
onRender: (item: Project) => (
<span
style={{
fontWeight: 'bold',
color: '#0078d4',
cursor: 'pointer',
textDecoration: 'underline',
}}
onClick={() => handleProjectClick(item)}
onMouseOver={(e) => (e.currentTarget.style.color = '#005a9e')}
onMouseOut={(e) => (e.currentTarget.style.color = '#0078d4')}
>
{item.name}
</span>
),
},
];
// Handle project click to show modal
const handleProjectClick = (project: Project) => {
setSelectedProject(project);
showModal();
};
// Filter projects based on input text
const filteredProjects = projects.filter(project =>
project.name.toLowerCase().includes(filterText.toLowerCase())
);
In this code:
columnsdefine the structure and style for each project entry in the list.handleProjectClickopens the modal when a project name is clicked.
Step 3: Adding a Title Bar and Rendering Components
We’ll add a custom title bar and integrate TextField, DetailsList, and Modal components.
return (
<div>
{/* Title Bar */}
<div style={{
backgroundColor: '#0078d4',
color: 'white',
padding: '10px',
fontWeight: 'bold',
textAlign: 'center',
marginBottom: '20px'
}}>
Meus Projetos
</div>
{/* Filter TextField */}
<TextField
label="Filter by Project Name"
value={filterText}
onChange={(_, newValue) => setFilterText(newValue || '')}
styles={{ root: { marginBottom: 20 } }}
/>
{/* Project List */}
<DetailsList
items={filteredProjects}
columns={columns}
setKey="set"
layoutMode={0}
selectionMode={0}
/>
{/* Modal for Project Details */}
<Modal
isOpen={isModalOpen}
onDismiss={hideModal}
isBlocking={false}
titleAriaId="modal-title"
styles={{
main: {
backgroundColor: '#f3f2f1',
width: '60%',
height: '60%',
top: '20%',
left: '20%',
overflow: 'hidden',
},
}}
>
{selectedProject && (
<div>
<h2 id="modal-title" style={{ color: 'white', backgroundColor: '#0078d4', padding: '10px' }}>
{selectedProject.name}
</h2>
<p>{selectedProject.description}</p>
<span style={{ cursor: 'pointer', color: '#0078d4' }} onClick={hideModal}>
Close
</span>
</div>
)}
</Modal>
</div>
);
};
export default ProjectList;
In this part:
- Title Bar: Displays the “Meus Projetos” title at the top, with custom styles for color and spacing.
- Filter Input:
TextFieldallows users to filter projects by name. - Project List:
DetailsListrenders the project data with column definitions. - Project Details Modal:
Modaldisplays detailed information about the selected project.
Full Code
Here’s the full component code:
import * as React from 'react';
import { useBoolean } from '@fluentui/react-hooks';
import { Modal, DetailsList, IColumn, TextField } from '@fluentui/react';
interface Project {
id: number;
name: string;
description: string;
}
const initialProjects: Project[] = [
{ id: 1, name: "Project A", description: "Description for Project A" },
{ id: 2, name: "Project B", description: "Description for Project B" },
{ id: 3, name: "Project C", description: "Description for Project C" },
];
const ProjectList: React.FunctionComponent = () => {
const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false);
const [selectedProject, setSelectedProject] = React.useState<Project | null>(null);
const [filterText, setFilterText] = React.useState<string>('');
const projects: Project[] = initialProjects;
const columns: IColumn[] = [
{
key: 'column1',
name: 'Project Name',
fieldName: 'name',
minWidth: 100,
maxWidth: 300,
onRender: (item: Project) => (
<span
style={{
fontWeight: 'bold',
color: '#0078d4',
cursor: 'pointer',
textDecoration: 'underline',
}}
onClick={() => handleProjectClick(item)}
onMouseOver={(e) => (e.currentTarget.style.color = '#005a9e')}
onMouseOut={(e) => (e.currentTarget.style.color = '#0078d4')}
>
{item.name}
</span>
),
},
];
const handleProjectClick = (project: Project) => {
setSelectedProject(project);
showModal();
};
const filteredProjects = projects.filter(project =>
project.name.toLowerCase().includes(filterText.toLowerCase())
);
return (
<div>
<div style={{ backgroundColor: '#0078d4', color: 'white', padding: '10px', fontWeight: 'bold', textAlign: 'center', marginBottom: '20px' }}>
Meus Projetos
</div>
<TextField
label="Filter by Project Name"
value={filterText}
onChange={(_, newValue) => setFilterText(newValue || '')}
styles={{ root: { marginBottom: 20 } }}
/>
<DetailsList
items={filteredProjects}
columns={columns}
setKey="set"
layoutMode={0}
selectionMode={0}
/>
<Modal
isOpen={isModalOpen}
onDismiss={hideModal}
isBlocking={false}
titleAriaId="modal-title"
styles={{
main: {
backgroundColor: '#f3f2f1',
width: '60%',
height: '60%',
top: '20%',
left: '20%',
overflow: 'hidden',
},
}}
>
{selectedProject && (
<div>
<h2 id="modal-title" style={{ color: 'white', backgroundColor: '#0078d4', padding: '10px' }}>
{selectedProject.name}
</h2>
<p>{selectedProject.description}</p>
<span style={{ cursor: 'pointer', color: '#0078d4' }} onClick={hideModal}>
Close
</span>
</div>
)}
</Modal>
</div>
);
};
export default ProjectList;
Conclusion
This ProjectList component provides a user-friendly interface for managing and viewing project data. It demonstrates how to use Fluent UI components and styles effectively to enhance the UI. You can expand this component by adding more project details or additional actions as needed.
