Building a React Menu does't have to be daunting. And let's use style-components while we're at it! 🔥
This may not be the most advanced React Nav, or showcase best practices, but it will get you up and running in no time!
Let's just get right into it D:
Check Out The Demo!
The Repo
Things I'll assume you have some knowledge of
- Dev Environment. Ex. Node, VSCode..etc.
- Know how to install NPM packages
- Have some knowledge of React
- Have some knowledge of React Router
- Some basic CSS or SCSS
1. Starting with Create-react-app
Start with a clean project. Remove the create-react-app pre-loaded files and don't forget to remove the lines of code related to testing in index.js. I also remove everything in App.js other than App.css. Remove everything inside of App.css leaving only the .App css selector with min-height: 100vh , background-color: #282c34, and position: relative
Your project should look like this

And App.css should look like so

2. A Clean directory
Create a
componentsfolder and apagesfolder.Inside the
componentsfolder include 2 files:Menu.jsandToggle.js.Inside the
pagesfolder include 3 files:HomePage.js,ExamplePage.js,ContactPage.js.
3. Turn files into functional components
Your HomePage.js , ExamplePage.js , and ContactPage.js should now look like this.
HomePage

ExamplePage

ContactPage

4. Install styled-components
I prefer using Yarn package manager, so to install styled-components run this command: yarn add styled-components. If you are using NPM use this command: npm install --save styled-components. Make sure to import styled-components in each of our three pages like so: import styled from styled-components.
5. Adding styled-components our pages
The HomePage, ExamplePage and ContactPage should all share the same layout and styled-components. So just copy and paste. Don't forget to change the appropriate page name in Heading component.
6. Install react-router-dom
- Install react-router-dom into our project.
yarn add react-router-dom. Ornpm install --save react-router-dom. - Import react router like so:
import { BrowserRouter as Router, Route, Switch } from react-router-dom. - Import our
pagesfiles intoApp.jsso we can make use of React Router. Import the pages like so:import HomePage from ./pages/HomePage;import ExamplePage from ./pages/ExamplePage;import ContactPage from ./pages/ContactPage; - Refer to the photo below on how to use React Router in
App()
So far App.js should look like this

If everything has gone smoothly so far, react router should be working. In the URL, try changing the path to localhost:3000/example or to /contact
7. Complete Menu and Toggle components
- In step 2 we created a
Menu.jsandToggle.jsfiles in the components folder. Let's turn those into functional components. Starting with
Menu.jslet' importLinkfrom react-router-dom like so:import { Link } from 'react-router-dom'). We're also going to make use of some Icons. I preferhttps://react-icons.github.io/react-icons/because of simplicity. So let's install react-icons like so:yarn add react-iconsAlso, be sure to import the icons like so:import { FaBars, FaTimes} from 'react-icons/fa'. Don't forget to add/faas we are importing from theFont Awesomelibrary. Feel free to use any library, just browse the website mentioned above. If you were to use anIconfrom theMateriallibrary, you would import the file like so:import { MdBars} from 'react-icons/md'. Files should like like this


Starting with
Menu.jslets once again import styled components like so:import styled from styled-components.
You'll notice I passedLinkdirectly intoStyledLinkrather than having to create an<a>anchor/</a>tag in the DOM. All we need to do is add thetoattribute to ourStyledLink.Then let's create our styled components for
Menu.js. Starting with theStyledMenucomponent. It should like like this
Followed by our
StyledMenuwe need links for our Menu so users can click to navigate pages. Should look like this
Now we need a way to switch toggle states. If the Menu is toggled or it's state is set to
true, we need a way to close the Menu by toggling the state tofalse. Let's add a simple toggle button to our Menu. It should look like this
Last thing for our Menu is to add our styled-components to our
Menu()like so. Don't forget to add theto='*'attribute to your links. These are required for ourRouterinApp.jsto understand which views should be rendered once a user clicks the corresponding link. For ex. if your user was to click on the/contactlink, theContactcomponent inApp.jswould be rendered as we declared it's path to look like thispath='/contact'.

Lastly we have
Toggle.js. TheTogglecomponent is the most basic. It's only responsible for changing our toggle state for ourMenu. We have already turned it into a functional component, so let's first begin with importingstyled-componentsandreact-iconslike soimport styled from 'styled-components'andimport { FaBars } from 'react-icons/fa'. Lastly, let's create theStyledTogglecomponent, add it to our emptyToggle()component then add ourFaBarsicon like so

8. Let's make use of our newly made components
Back in
App.js, just like we imported ourpagescomponents, let's import ourMenu.jsandToggle.jscomponents like so

You should notice our Menu is being rendered. It's already working. You should also notice our
CloseTogglebutton in the top right corner of our Menu. However, what you won't see is ourTogglebutton, because theMenuis blocking it. Let's fix this by addingstateto our App with theuseState()hook. At the top of your app, import the hook like so:import { useState } from 'react'. Now for our state, we need to be able to the hold the value of our toggled state, and be able to switch toggle states. It should look like this

We initially have ournavToggledstate set to false, because when a user lands on our website, the Menu should not be rendered. So logically, it makes to most sense to have the state initially set tofalse.To further make use of our
useStatehook, let's create a function for toggling our state. Let's call itsetNavToggle. This functions only responsibility is to toggle the opposite state of whatever our currentnavToggledstate is. For instance, if our currentnavToggledstate is set to false, when the function is called, it'll set the new state to the opposite of false, making it true. If thenavToggledstate was true, the function will change the state to the of that value, making it true. It should look like this

Now that we have a way to handle our Menus toggle state, let's make use of it by adding it to our
Menucomponent. That way we can toggle our Menu tofalse. To do so, we are going to passhandleNavToggleto ourMenucomponent as a prop. Like so

Now that we have passed our handler function to our
Menucomponent as a prop, we now have the ability to change our state from within theMenucomponent. But first let's accept the passed in prop from within ourMenucomponent first. Like so

Now our intention is to be able to close the Menu, or toggle the Menus state to
false. Let's do that by adding a click event listener ourCloseTogglecomponent, then pass in ourhandleNavToggle. In React, you need to use camelCase, so it should like soonClick={handleNavToggle}

You'll notice if you click the
CloseTogglebutton, nothing is happening. That's because back inApp.jswe are forcing the render of ourMenucomponent, no matter the state. Let's fix that by dynamically rendering ourMenucomponent by using a ternary operator. It should look like this

I'll explain in pseudocode. Here we are saying,if the navToggle state is true ?render<Menu/>: if its not, then return null. We're looking to see if the value of what's on the left of the?istrue. In this case, we're looking to see if theNavToggledstate is true. If thenavTogglestate is indeed true, we're then going to render whatever is on the right side of the?. And if it is not true, just like an if else statement, we're going to render whatever is on the right side of the:. In this case, we want to render nothing. So we usenull. Essentially, it'sif ? do this : else do this.
You should also notice that if you try to toggle theCloseTogglebutton, that it works. Because we are only rendering theMenuif the state istrue.You'll also notice if we attempt to toggle theMenuagain, nothing happens.Let's add functionality to our
Togglecomponent! Back inApp.js, we just pass in our handler function as a prop to ourTogglecomponent like so

Back in
Toggle.jslets again accept our passed in handler function by restructuring it like so

Now add our function as a click event to the
StyledTogglelike so

If everything has gone smoothly so far, it should be fully
functional, and fully responsive!
9. 👏 Congrats! 🔥
You have successfully built a fully responsive React navigation with Styled-components! If it's not exactly turning out as planned, I am more than happy to help you find the solution! Either use the comments section below, or DM me on Twitter!
10. Bonus animations!
Let's make our React app even better with some swanky animations.
We're going to use
animate.css. It's a lightweight animation library, and it's very easy to implement into react apps. Install like soyarn add animate.css, ornpm install --save animate.cssInside of
index.jsbelowimport App from './App';addimport 'animate.css';And just like that our entire app has access to
animate.css.Let's first add some animations to our
Linkcomponents and our singleCloseTogglecomponent inMenu.js. Like soclassName="animate__animated animate__fadeInRight"

Just like that, we should have some slick animations in our Menu. Be careful to not get carried away with animations. It's not recommended to add animations to the entireparent div. For example, you should not add these sort of animations to the entireStyledMenucomponent as it can cause some performance issues!Lastly, back in
HomePage.js,ExamplePage.jsandContactPage.js, let's do something similar. Let's add some animations to ourHeadingcomponent. Like thisclassName="animate__animated animate__fadeInLeft". Heres an example ofHomePage.js

Conclusion! 👋
That's a wrap on How to build a Responsive 📱 React Navigation Menu with Styled-Components 💻. If you made it this far, you have a lot of time on your hands. Lol 🤣 Thank you so much for your time, and I hope it was successful!
Please don't hesitate to hit me up on Twitter in regards to any questions, concerns or if you just wanna talk code!
Happy coding! ✌️





Top comments (7)
Hi, I've just had a quick look at your demo and it looks like your menu is not accessible without a mouse. This would be a quick fix you can use styled buttons rather than the icons directly as the buttons come with keyboard support out the box.
Hey there, thanks for letting me know. You mean it's not accessible with a keyboard? Because it works with mobile D: Unless that's obvious, but you're strictly speaking about keyboard accessible! I'll check it out 👍
Yes sorry i mean not accessible without pointer input (so mouse or touch)
Hey no worries! I just fixed the issue. I left the default button styles too, because I think it looks bad ass! Haha. Works with the theme.
Also, thanks for sharing your thoughts. I see your'e into accessibility, and I think we all should be. I'd like to spend more time concentrating on accessibility while coding. I appreciate it✌️
Hi. I have done the same thing but I can't understand where I am making the mistake. The browser just displays the background only. Here is my app.css which i don't think the problem is coming from. However, the home page (and any other page) is not displayed at all
.App {
min-height: 100vh;
background-color: black;
position: relative;
}
Hey, that suck! Well let's figure it out.
First, are you using dev tools? Like chrome dev tools on the chrome browser? Firefox works well too.
Secondly, are you sure you have React router set up correctly? React-router just had an update, so you should be made aware. It's now React Router v6. I believe it's breaking changes if you don't have a production app yet. Minor changes tho, look at the docs, they show the old vs new way.
Thirdly, your body text made relative to your #000 background color?
Let's start here.
Thanks so much for your feedback. Yes I am using Chrome Dev Tools. The body text is different from the background colour. I realised that my React-Router wasn't set up correctly as you have stated, I did an update and it worked. Thanks for the assistance.