I created a sidebar menu with the help of react and tailwindcss.
When the user clicks on the hamburger icon (menu), the sidebar appears with a slight animation as it appears from left to right. I’m currently trying to do the same animation after the user leaves the sidebar, in the reverse direction (sidebar disappearing from right to left), but it honestly doesn’t work for me. I’ve tried many things, but it seems like something in the code itself is stopping such an animation from working.
Can you take a look at the code and try to explain to me the best way to achieve this effect and the goal I set for myself?
This is my react Menu component:
import React, { useRef, useState } from 'react';
import Sidebar from "./Sidebar";
const Menu = ({ sidebarOpen, toggleSidebar }) => {
const containerRef = useRef(null);
const sidebarRef = useRef(null);
const [animationComplete, setAnimationComplete] = useState(false);
const handleToggleSidebar = () => {
if (!sidebarOpen) {
setAnimationComplete(false);
}
toggleSidebar(!sidebarOpen);
};
React.useEffect(() => {
if (sidebarOpen) {
document.body.classList.add("sidebar-open");
document.body.style.overflow = "hidden";
} else {
document.body.classList.remove("sidebar-open");
document.body.style.overflow = "auto";
}
}, [sidebarOpen]);
React.useEffect(() => {
if (sidebarOpen && containerRef.current && !animationComplete) {
const sidebarElement = sidebarRef.current;
sidebarElement.style.transform = "translateX(-100%)";
sidebarElement.style.transition = "transform 0s";
requestAnimationFrame(() => {
sidebarElement.style.transform = "translateX(0)";
sidebarElement.style.transition = "transform 0.5s";
setAnimationComplete(true);
});
}
}, [sidebarOpen, animationComplete]);
return (
<div className="fixed bottom-0 left-0 w-full bg-white z-50 border-t-1 border-green-900">
<div className="h-[60px] flex items-center justify-between">
<div className="flex items-center ml-4">
<div
ref={containerRef}
className="cursor-pointer p-3"
onClick={handleToggleSidebar}
>
<div className={`h-1 w-6 bg-green-700 rounded mb-1 ${sidebarOpen ? 'opacity-0' : ''}`}></div>
<div className={`h-1 w-6 bg-green-700 rounded mb-1 ${sidebarOpen ? 'opacity-0' : ''}`}></div>
<div className={`h-1 w-6 bg-green-700 rounded ${sidebarOpen ? 'opacity-0' : ''}`}></div>
</div>
</div>
</div>
{sidebarOpen && (
<>
<div className="fixed top-0 left-0 right-0 bottom-0 z-0 bg-gray-700 opacity-50" onClick={() => toggleSidebar(false)}></div>
<div ref={sidebarRef} className="fixed top-0 left-0 bottom-0 z-10 w-full max-w-[20rem] p-4 bg-white shadow-xl shadow-blue-gray-900/5">
<Sidebar />
</div>
</>
)}
</div>
);
}
export default Menu;
This is custom css sidebar-open:
body.sidebar-open {
overflow: hidden;
}
This is not relevant at all, but you can also take a look into my Sidebar component (since its mentioned in the Menu component:
function scrollToTop() {
window.scrollTo(0, 0);
}
const Sidebar = forwardRef((props, ref) => {
const [open, setOpen] = React.useState(0);
const [openAlert, setOpenAlert] = React.useState(true);
const handleOpen = (value) => {
setOpen(open === value ? 0 : value);
};
return (
<Card ref={ref} className="fixed top-0 left-0 h-[calc(100vh-2rem)] w-full max-w-[20rem] p-4 shadow-xl shadow-blue-gray-900/5 overflow-y-auto">
<List>
<Accordion
open={open === 1}
icon={
<ChevronDownIcon
strokeWidth={2.5}
className={`mx-auto h-4 w-4 transition-transform ${open === 1 ? "rotate-180" : ""}`}
/>
}
>
<Link to="/home" onClick={scrollToTop}>
<ListItem className="focus:bg-green-50 hover:bg-green-50">
<ListItemPrefix>
<HomeIcon className="h-5 w-5 text-green-900" />
</ListItemPrefix>
<Typography color="blue-gray" className="mr-auto font-normal">
Home
</Typography>
</ListItem>
</Link>
<ListItem className="p-0 focus:bg-green-50 hover:bg-green-50" selected={open === 1}>
<AccordionHeader onClick={() => handleOpen(1)} className="border-b-0 p-3">
<ListItemPrefix>
<PresentationChartBarIcon className="h-5 w-5 text-green-900" />
</ListItemPrefix>
<Typography color="blue-gray" className="mr-auto font-normal">
Dashboard
</Typography>
</AccordionHeader>
</ListItem>
<AccordionBody className="py-1">
<List className="p-0">
<Link to="/balance" onClick={scrollToTop}>
<ListItem className="focus:bg-green-50 hover:bg-green-50">
<ListItemPrefix>
<ChevronRightIcon strokeWidth={3} className="h-3 w-5" />
</ListItemPrefix>
Balance
</ListItem>
</Link>
etc...
NOTE: I cut some irrelevant code for simplicity and that’s why I have some extra tailwindcss properties in the code.