Mastering Mobile Navigation Menus in React

The Challenge of Full-Page Menus

When designing mobile navigation menus, we often encounter a common problem: how to prevent scrolling on the underlying page while keeping the menu open. One solution is to add position: fixed to the original page, but this introduces another issue – losing the current scroll position when closing the menu.

A Custom Hook to the Rescue

To overcome these challenges, we’ll create a custom Hook in a React application that allows us to stop the page from scrolling when a full-page mobile menu is open, while maintaining the scroll position when the menu is closed.

Setting Up the Frontend

First, let’s create a new React application using create-react-app. Once set up, we can build a simple frontend to demonstrate our custom Hook.

The Code

Here’s the code for our App.js file:
“`
//./src/App.js
import React, { useState, useEffect } from ‘eact’;

function App() {
const [scrollPosition, setScrollPosition] = useState(0);

useEffect(() => {
const handleScroll = () => {
setScrollPosition(window.scrollY);
};
window.addEventListener(‘scroll’, handleScroll);
return () => {
window.removeEventListener(‘scroll’, handleScroll);
};
}, []);

return (

Mobile Navigation Menu

Current scroll position: {scrollPosition}

);
}

export default App;

And here's the styling for our `App.js` file:

/*./src/App.css */
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
“`
Creating the Mobile Navigation Menu

Next, let’s create a Nav.js component to house our mobile navigation menu:
“`
//./src/components/Nav.js
import React from ‘eact’;

function Nav() {
return (

);
}

export default Nav;

**The
useMenuControl` Custom Hook**

Now, let’s create our custom Hook, useMenuControl, to control the full-page mobile menu opening and closing, as well as maintaining the scroll position:
“`
//./src/hooks/useMenuControl.js
import { useState, useEffect } from ‘eact’;

function useMenuControl() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [originalOverflow, setOriginalOverflow] = useState(”);

useEffect(() => {
if (isMenuOpen) {
setOriginalOverflow(document.body.style.overflow);
document.body.style.overflow = ‘hidden’;
} else {
document.body.style.overflow = originalOverflow;
}
}, [isMenuOpen]);

const clickHandler = () => {
setIsMenuOpen(!isMenuOpen);
};

return [isMenuOpen, clickHandler];
}

export default useMenuControl;
“`
Implementing the Custom Hook

Let’s revisit our Nav component and add the useMenuControl custom Hook:
“`
//./src/components/Nav.js
import React from ‘eact’;
import useMenuControl from ‘../hooks/useMenuControl’;

function Nav() {
const [isMenuOpen, clickHandler] = useMenuControl();

return (

);
}

export default Nav;

And finally, let's add some styles for the `.menuOpen` class:

/*./src/components/Nav.css */
.menuOpen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: #fff;
z-index: 1;
}
“`
The Final Result

With these pieces in place, we now have a React application that allows us to open a full-page mobile menu, maintaining the scroll position on the page underneath, while preventing scrolling on the page while the menu is open.

Check out the final version of this application on GitHub, and follow me on Twitter for more helpful tips and content on the JavaScript ecosystem and web development.

Leave a Reply

Your email address will not be published. Required fields are marked *