Building a Draggable Dashboard with React Using react-grid-layout Library


In modern web development, creating interactive and responsive dashboards is a common requirement. React, being a popular JavaScript library for building user interfaces, offers a plethora of tools and libraries to accomplish such tasks efficiently. One such library is react-grid-layout
, which provides a flexible grid layout system for React applications. In this blog post, we'll explore how to create a draggable dashboard with customizable components using react-grid-layout
.
Introduction to react-grid-layout
react-grid-layout
is a powerful React library that enables developers to create draggable, resizable grid layouts. It allows you to arrange UI components within a grid-based layout, providing users with the ability to customize the layout according to their preferences. With features like responsive layouts, dynamic resizing, and drag-and-drop functionality, it's an excellent choice for building interactive dashboards.
Project Overview
For this project, we'll be creating a dashboard with various components such as object alerts, driver alerts, object health, and more. Users can rearrange these components within the dashboard by dragging and dropping them, providing a personalized dashboard experience. Additionally, we'll integrate features like local storage to persist layout changes across sessions, making the dashboard more user-friendly.
Setting Up the Project
To get started, make sure you have Node.js and npm installed on your system. Create a new React project using create-react-app
or any other preferred method. Once your project is set up, install the required dependencies:
npm install react-grid-layout react-resizable @mui/material @mui/icons-material
Import the required hooks and dependencies
import React, { useEffect, useState, useCallback } from "react";
import { Responsive, WidthProvider } from "react-grid-layout";
import { Box, IconButton, Paper, Typography } from "@mui/material";
import { FilterAltOutlined, SettingsOutlined } from "@mui/icons-material";
import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";
const ResponsiveGridLayout = WidthProvider(Responsive);
Starting the component
const App = () => {
const [value, setValue] = useState(true);
const initialLayout = JSON.parse(localStorage.getItem("layout")) || {
lg: [
{ i: "a", x: 0, y: 0, w: 4, h: 1 },
{ i: "b", x: 4, y: 0, w: 2, h: 0.5 },
{ i: "c", x: 8, y: 0, w: 4, h: 0.5 },
{ i: "d", x: 0, y: 1, w: 2, h: 0.5 },
{ i: "e", x: 4, y: 1, w: 4, h: 1 },
{ i: "f", x: 8, y: 1, w: 4, h: 1 },
{ i: "g", x: 0, y: 2, w: 2, h: 0.5 },
{ i: "h", x: 2, y: 2, w: 4, h: 0.5 },
{ i: "i", x: 6, y: 2, w: 2, h: 0.5 },
{ i: "j", x: 0, y: 3, w: 6, h: 1 },
],
};
console.log("rendering");
const [layout, setLayout] = useState(initialLayout);
useEffect(() => {
// Save layout to local storage whenever it changes
localStorage.setItem("layout", JSON.stringify(layout));
}, [layout]);
// Function to handle layout change
// Function to handle layout change
const onLayoutChange = useCallback((newLayout) => {
localStorage.setItem("layout", JSON.stringify({ lg: newLayout }));
// setLayout({ lg: newLayout });
}, []);
Here we have declared the state to store the initial layout values ,initially the components will be spread out in the below dimensions ,as of now i have 9 components and there are 9 initial dimensions
lg: [
{ i: "a", x: 0, y: 0, w: 4, h: 1 },
{ i: "b", x: 4, y: 0, w: 2, h: 0.5 },
{ i: "c", x: 8, y: 0, w: 4, h: 0.5 },
{ i: "d", x: 0, y: 1, w: 2, h: 0.5 },
{ i: "e", x: 4, y: 1, w: 4, h: 1 },
{ i: "f", x: 8, y: 1, w: 4, h: 1 },
{ i: "g", x: 0, y: 2, w: 2, h: 0.5 },
{ i: "h", x: 2, y: 2, w: 4, h: 0.5 },
{ i: "i", x: 6, y: 2, w: 2, h: 0.5 },
{ i: "j", x: 0, y: 3, w: 6, h: 1 },
],
Whenever layout changes ,the changed layout is stored in local storage
useEffect(() => {
// Save layout to local storage whenever it changes
localStorage.setItem("layout", JSON.stringify(layout));
}, [layout]);
function to handle layout change
// Function to handle layout change
const onLayoutChange = useCallback((newLayout) => {
localStorage.setItem("layout", JSON.stringify({ lg: newLayout }));
// setLayout({ lg: newLayout });
}, []);
So that was the functionality part,below is the jsx part
<Box
sx={{
width: "98%",
marginLeft: "1.1rem",
marginTop: "0.8rem",
height: "98.2vh",
overflowY: "auto",
}}
component={Paper}
>
{/* <Navbar /> */}
<Box
sx={{
width: "98.1%",
backgroundColor: "#b5592a",
display: "flex",
justifyContent: "space-between",
padding: "1rem",
alignItems: "center",
top: 0,
position: "sticky",
zIndex: "100",
}}
>
<Typography
sx={{ color: "white", fontSize: "1.4rem", fontWeight: "500" }}
>
Dashboard
</Typography>
<Box>
<IconButton>
<FilterAltOutlinedIcon
sx={{ color: "white", height: "2rem", width: "2.5rem" }}
/>
</IconButton>
<IconButton>
<SettingsOutlinedIcon
sx={{ color: "white", height: "2rem", width: "2.5rem" }}
/>{" "}
</IconButton>
</Box>
</Box>
<ResponsiveGridLayout
className="layout"
layouts={layout}
breakpoints={{ lg: 1200 }}
cols={{ lg: 12 }}
rowHeight={410}
width={1200}
isResizable={false}
onLayoutChange={onLayoutChange}
>
<Box key="a" component={Paper}>
{/* <DemoComponent color={"yellow"} /> */}
<ObjectAlerts />
</Box>
<Box key="b" component={Paper} style={{ backgroundColor: " #7dd87d" }}>
{/* <DemoComponent color={"green"} /> */}
<Address />
</Box>
<Box key="c" component={Paper}>
{/* <DemoComponent color={"red"} /> */}
<Fleet />
</Box>
<Box key="d" component={Paper} style={{ backgroundColor: "#E6E6FA" }}>
{/* <DemoComponent color={"blue"} /> */}
<Fence />
</Box>
<Box
key="e"
component={Paper}
// style={{ backgroundColor: "violet" }}
>
{/* <DemoComponent color={"violet"} /> */}
<DriverAlerts />
</Box>
<Box
key="f"
component={Paper}
// style={{ backgroundColor: "lemonchiffon" }}
>
{/* <DemoComponent color={"lemonchiffon"} /> */}
<ObjectHealth />
</Box>
<Box key="g" component={Paper} style={{ backgroundColor: "#aef4a4" }}>
{/* <DemoComponent color={"blue"} /> */}
<Zone />
</Box>
<Box
key="h"
component={Paper}
// style={{ backgroundColor: "green" }}
>
{/* <DemoComponent color={"green"} /> */}
<ObjectMode />
</Box>
<Box key="i" component={Paper} style={{ backgroundColor: "#fff" }}>
{/* <DemoComponent color={"red"} /> */}
<Average />
</Box>
</ResponsiveGridLayout>
</Box>
here i have a kind of navbar and below that i am rendering the draggable dashboard components
Refer to the link for code
Subscribe to my newsletter
Read articles from Nikhil Kumar Khuntia directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
