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
components
folder and apages
folder.Inside the
components
folder include 2 files:Menu.js
andToggle.js
.Inside the
pages
folder 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
pages
files intoApp.js
so 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.js
andToggle.js
files in the components folder. Let's turn those into functional components. Starting with
Menu.js
let' importLink
from 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-icons
Also, be sure to import the icons like so:import { FaBars, FaTimes} from 'react-icons/fa'
. Don't forget to add/fa
as we are importing from theFont Awesome
library. Feel free to use any library, just browse the website mentioned above. If you were to use anIcon
from theMaterial
library, you would import the file like so:import { MdBars} from 'react-icons/md'
. Files should like like this
Starting with
Menu.js
lets once again import styled components like so:import styled from styled-components
.
You'll notice I passedLink
directly intoStyledLink
rather than having to create an<a>anchor/</a>
tag in the DOM. All we need to do is add theto
attribute to ourStyledLink
.Then let's create our styled components for
Menu.js
. Starting with theStyledMenu
component. It should like like thisFollowed by our
StyledMenu
we need links for our Menu so users can click to navigate pages. Should look like thisNow 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 thisLast 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 ourRouter
inApp.js
to understand which views should be rendered once a user clicks the corresponding link. For ex. if your user was to click on the/contact
link, theContact
component inApp.js
would be rendered as we declared it's path to look like thispath='/contact'
.
Lastly we have
Toggle.js
. TheToggle
component 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-components
andreact-icons
like soimport styled from 'styled-components'
andimport { FaBars } from 'react-icons/fa'
. Lastly, let's create theStyledToggle
component, add it to our emptyToggle()
component then add ourFaBars
icon like so
8. Let's make use of our newly made components
Back in
App.js
, just like we imported ourpages
components, let's import ourMenu.js
andToggle.js
components like so
You should notice our Menu is being rendered. It's already working. You should also notice our
CloseToggle
button in the top right corner of our Menu. However, what you won't see is ourToggle
button, because theMenu
is blocking it. Let's fix this by addingstate
to 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 ournavToggled
state 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
useState
hook, 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 currentnavToggled
state is. For instance, if our currentnavToggled
state is set to false, when the function is called, it'll set the new state to the opposite of false, making it true. If thenavToggled
state 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
Menu
component. That way we can toggle our Menu tofalse
. To do so, we are going to passhandleNavToggle
to ourMenu
component as a prop. Like so
Now that we have passed our handler function to our
Menu
component as a prop, we now have the ability to change our state from within theMenu
component. But first let's accept the passed in prop from within ourMenu
component 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 ourCloseToggle
component, then pass in ourhandleNavToggle
. In React, you need to use camelCase, so it should like soonClick={handleNavToggle}
You'll notice if you click the
CloseToggle
button, nothing is happening. That's because back inApp.js
we are forcing the render of ourMenu
component, no matter the state. Let's fix that by dynamically rendering ourMenu
component 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 theNavToggled
state is true. If thenavToggle
state 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 theCloseToggle
button, that it works. Because we are only rendering theMenu
if the state istrue.
You'll also notice if we attempt to toggle theMenu
again, nothing happens.Let's add functionality to our
Toggle
component! Back inApp.js
, we just pass in our handler function as a prop to ourToggle
component like so
Back in
Toggle.js
lets again accept our passed in handler function by restructuring it like so
Now add our function as a click event to the
StyledToggle
like 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.css
Inside of
index.js
belowimport 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
Link
components and our singleCloseToggle
component 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 entireStyledMenu
component as it can cause some performance issues!Lastly, back in
HomePage.js
,ExamplePage.js
andContactPage.js
, let's do something similar. Let's add some animations to ourHeading
component. 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.