Hello guys, how are you? Welcome back to my blog therichpost.com. Today in this post I will tell you How to Build a User Management System in the Berry React Admin Dashboard (Complete Guide + MUI Tutorial).
For react js new comers, please check the below links:

Project Setup
Clone the Berry free template:
git clone https://github.com/codedthemes/berry-free-react-admin-template
cd berry-free-react-admin-template
npm install
npm start
Step 1: Create the User Management Page(UserManagement.jsx) inside views folder and add below code inside it:
import React, { useEffect, useState } from "react";
import {
Box,
Typography,
TextField,
Button,
Table,
TableHead,
TableBody,
TableRow,
TableCell,
TableContainer,
Paper,
TablePagination,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
MenuItem,
Select,
FormControl,
InputLabel,
IconButton,
Stack,
} from "@mui/material";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/Delete";
export default function UserManagement() {
const [users, setUsers] = useState([]);
const [query, setQuery] = useState("");
// pagination state
const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(8);
// dialog state
const [open, setOpen] = useState(false);
const [editingUser, setEditingUser] = useState(null);
// form state
const [form, setForm] = useState({ name: "", email: "", role: "user", status: "active" });
const STORAGE_KEY = "berry_users_v1";
function loadFromStorage() {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) {
const seed = [
{ id: 1, name: "Alice Johnson", email: "alice@example.com", role: "admin", status: "active" },
{ id: 2, name: "Bob Smith", email: "bob@example.com", role: "user", status: "inactive" },
{ id: 3, name: "Cecilia Brown", email: "cecilia@example.com", role: "user", status: "active" },
];
localStorage.setItem(STORAGE_KEY, JSON.stringify(seed));
return seed;
}
try {
return JSON.parse(raw);
} catch (e) {
console.error("Failed to parse users from storage", e);
return [];
}
}
function saveToStorage(list) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(list));
}
useEffect(() => {
setUsers(loadFromStorage());
}, []);
// --- Dialog handlers ---
function handleOpenAdd() {
setEditingUser(null);
setForm({ name: "", email: "", role: "user", status: "active" });
setOpen(true);
}
function handleOpenEdit(user) {
setEditingUser(user);
setForm({ name: user.name, email: user.email, role: user.role, status: user.status });
setOpen(true);
}
function handleClose() {
setOpen(false);
}
function handleDelete(id) {
if (!window.confirm("Delete this user?")) return;
const updated = users.filter((u) => u.id !== id);
setUsers(updated);
saveToStorage(updated);
// adjust page if needed
const maxPage = Math.max(0, Math.ceil(updated.length / rowsPerPage) - 1);
setPage((p) => Math.min(p, maxPage));
}
function handleSubmit(e) {
e && e.preventDefault();
if (!form.name.trim() || !form.email.trim()) {
alert("Name and email are required.");
return;
}
if (editingUser) {
const updated = users.map((u) => (u.id === editingUser.id ? { ...u, ...form } : u));
setUsers(updated);
saveToStorage(updated);
} else {
const nextId = users.length ? Math.max(...users.map((u) => u.id)) + 1 : 1;
const newUser = { id: nextId, ...form };
const updated = [newUser, ...users];
setUsers(updated);
saveToStorage(updated);
setPage(0);
}
setOpen(false);
}
// --- Filtering + paging ---
const filtered = users.filter((u) => {
const q = query.toLowerCase();
return (
u.name.toLowerCase().includes(q) ||
u.email.toLowerCase().includes(q) ||
u.role.toLowerCase().includes(q) ||
u.status.toLowerCase().includes(q)
);
});
const emptyRows = Math.max(0, (1 + page) * rowsPerPage - filtered.length);
const paginated = filtered.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage);
// --- Table pagination handlers ---
const handleChangePage = (event, newPage) => {
setPage(newPage);
};
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
};
return (
<Box sx={{ p: 3 }}>
<Stack direction="row" alignItems="center" justifyContent="space-between" mb={2}>
<Typography variant="h5">User Management</Typography>
<Stack direction="row" spacing={2}>
<TextField
size="small"
placeholder="Search by name, email, role, status"
value={query}
onChange={(e) => { setQuery(e.target.value); setPage(0); }}
sx={{ width: 320 }}
/>
<Button variant="contained" onClick={handleOpenAdd}>Add User</Button>
</Stack>
</Stack>
<Paper elevation={1}>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Email</TableCell>
<TableCell>Role</TableCell>
<TableCell>Status</TableCell>
<TableCell align="right">Actions</TableCell>
</TableRow>
</TableHead>
<TableBody>
{paginated.length === 0 && (
<TableRow>
<TableCell colSpan={5} align="center">
No users found.
</TableCell>
</TableRow>
)}
{paginated.map((u) => (
<TableRow key={u.id} hover>
<TableCell>{u.name}</TableCell>
<TableCell>{u.email}</TableCell>
<TableCell>{u.role}</TableCell>
<TableCell>{u.status}</TableCell>
<TableCell align="right">
<IconButton size="small" onClick={() => handleOpenEdit(u)} aria-label="edit">
<EditIcon fontSize="small" />
</IconButton>
<IconButton size="small" onClick={() => handleDelete(u.id)} aria-label="delete">
<DeleteIcon fontSize="small" />
</IconButton>
</TableCell>
</TableRow>
))}
{emptyRows > 0 && (
<TableRow style={{ height: 53 * emptyRows }}>
<TableCell colSpan={5} />
</TableRow>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
component="div"
count={filtered.length}
page={page}
onPageChange={handleChangePage}
rowsPerPage={rowsPerPage}
onRowsPerPageChange={handleChangeRowsPerPage}
rowsPerPageOptions={[5, 8, 10, 25]}
/>
</Paper>
{/* Add / Edit Dialog */}
<Dialog open={open} onClose={handleClose} fullWidth maxWidth="sm">
<DialogTitle>{editingUser ? "Edit User" : "Add User"}</DialogTitle>
<DialogContent>
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1, display: "grid", gap: 2 }}>
<TextField
label="Full name"
fullWidth
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
/>
<TextField
label="Email"
fullWidth
value={form.email}
onChange={(e) => setForm({ ...form, email: e.target.value })}
/>
<Stack direction="row" spacing={2}>
<FormControl fullWidth>
<InputLabel id="role-label">Role</InputLabel>
<Select
labelId="role-label"
value={form.role}
label="Role"
onChange={(e) => setForm({ ...form, role: e.target.value })}
>
<MenuItem value="user">User</MenuItem>
<MenuItem value="admin">Admin</MenuItem>
<MenuItem value="manager">Manager</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel id="status-label">Status</InputLabel>
<Select
labelId="status-label"
value={form.status}
label="Status"
onChange={(e) => setForm({ ...form, status: e.target.value })}
>
<MenuItem value="active">Active</MenuItem>
<MenuItem value="inactive">Inactive</MenuItem>
<MenuItem value="pending">Pending</MenuItem>
</Select>
</FormControl>
</Stack>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button onClick={handleSubmit} variant="contained">Save</Button>
</DialogActions>
</Dialog>
</Box>
);
}
Step 2: Add Route for the New Page src/routes/MainRoutes.js(just replace this):
import { lazy } from 'react';
// project imports
import MainLayout from 'layout/MainLayout';
import Loadable from 'ui-component/Loadable';
// dashboard routing
const DashboardDefault = Loadable(lazy(() => import('views/dashboard/Default')));
// utilities routing
const UtilsTypography = Loadable(lazy(() => import('views/utilities/Typography')));
const UtilsColor = Loadable(lazy(() => import('views/utilities/Color')));
const UtilsShadow = Loadable(lazy(() => import('views/utilities/Shadow')));
// sample page routing
const SamplePage = Loadable(lazy(() => import('views/sample-page')));
const UserManagement = Loadable(lazy(() => import('views/UserManagement')));
// ==============================|| MAIN ROUTING ||============================== //
const MainRoutes = {
path: '/',
element: <MainLayout />,
children: [
{
path: '/',
element: <DashboardDefault />
},
{
path: 'dashboard',
children: [
{
path: 'default',
element: <DashboardDefault />
}
]
},
{
path: 'typography',
element: <UtilsTypography />
},
{
path: 'color',
element: <UtilsColor />
},
{
path: 'shadow',
element: <UtilsShadow />
},
{
path: '/sample-page',
element: <SamplePage />
},
{
path: '/users',
element: <UserManagement />
}
]
};
export default MainRoutes;
Step 3: Add Sidebar Navigation Link src/menu-items/other.js (just replace this):
// assets
import { IconBrandChrome, IconHelp, IconUser } from '@tabler/icons-react';
// constant
const icons = { IconBrandChrome, IconHelp, IconUser };
// ==============================|| SAMPLE PAGE & DOCUMENTATION MENU ITEMS ||============================== //
const other = {
id: 'sample-docs-roadmap',
type: 'group',
children: [
{
id: 'sample-page',
title: 'Sample Page',
type: 'item',
url: '/sample-page',
icon: icons.IconBrandChrome,
breadcrumbs: false
},
{
id: 'usermanagement',
title: 'User Management',
type: 'item',
url: '/users',
icon: icons.IconUser,
breadcrumbs: false
},
{
id: 'documentation',
title: 'Documentation',
type: 'item',
url: 'https://codedthemes.gitbook.io/berry/',
icon: icons.IconHelp,
external: true,
target: true
}
]
};
export default other;
Step 4 : Just test your page:
npm start
You’ll see the new User Management page inside the Material UI layout, with a sidebar link that’s fully functional.
You’ve just extended a professional Material UI dashboard with your own custom page — this skill is essential for building scalable admin systems.
Ajay
Thanks
