React: Super Simple Side Menu Example
Here we will create a simple slide menu in react that will close when you click outside of it. This is a common pattern that you will see in many applications. We will be using React hooks to accomplish this.
useOutsideClick.ts
First lets create a util hook called useOutsideClick
that will take a ref and a handler function. This hook will call the handler function when the user clicks outside of the ref.
import { useEffect, useCallback, useRef, type RefObject } from 'react'
function useOutsideClick<T extends HTMLElement>(
ref: RefObject<T>,
handler: (e: MouseEvent | TouchEvent) => void,
when: boolean = true,
): void {
const savedHandler = useRef(handler)
const memoizedCallback = useCallback((e: MouseEvent | TouchEvent) => {
if (ref && ref.current && !ref.current.contains(e.target as Node)) {
savedHandler.current(e)
}
}, [])
useEffect(() => {
savedHandler.current = handler
})
useEffect(
// eslint-disable-next-line
() => {
if (when) {
document.addEventListener('click', memoizedCallback)
document.addEventListener('touchstart', memoizedCallback)
return () => {
document.removeEventListener('click', memoizedCallback)
document.removeEventListener('touchstart', memoizedCallback)
}
}
},
[ref, handler, when],
)
}
export default useOutsideClick
Sidebar Component
Here we are using the useOutsideClick
hook to close the menu when the user clicks outside of the menu. We are also using the cn
package to conditionally add the side-menu--active
class to the menu when the toggle button is clicked.
import { useState, useRef } from "react";
import cn from "classnames";
import useOutsideClick from "./useOutsideClick";
import "./styles.css";
const Sidebar = () => {
const [toggle, setToggle] = useState(false);
const pRef = useRef();
const handleOutsideClick = () => setToggle(false);
useOutsideClick(pRef, handleOutsideClick);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div
className={cn("side-menu", toggle && "side-menu--active")}
ref={pRef}
>
<div>side menu</div>
<button
onClick={() => setToggle(!toggle)}
className="side-menu__toggle"
>
click
</button>
</div>
</div>
);
};
CSS
.side-menu {
position: absolute;
left: 0;
top: 20%;
height: 200px;
width: 100px;
background: tomato;
transform: translateX(-100%);
transition: all 300ms ease-in-out;
}
.side-menu__toggle {
position: absolute;
left: 100px;
top: 0;
background: tomato;
border: 0;
color: blue;
line-height: 2;
border-radius: 0 5px 5px 0;
cursor: pointer;
border-left: 1px solid black;
}
For our CSS we are using the transform
property to move the menu off the screen. We are also using the transition
property to animate the menu when it is opened and closed. Since this is the initial state of the menu it is set to translateX(-100%)
. When the menu is opened we will set the transform
property to translateX(0)
.
.side-menu--active {
transform: translateX(0);
}