Editor’s note: This article was updated by Taofiq Aiyelabegan on 1 February 2024 with a new demo using React Router DOM for dynamic routing, as well as to ensure all information aligns with recent developments in React and CSS. The new navbar demo also adds a CTA button and shows how to use either media queries or the useMediaQuery
Hook to handle responsiveness. You can view the original demo and source code on CodeSandbox.
Styling responsive navigation menus for end users is hardly ever an easy process. Frontend developers have to consider certain parameters — like device breakpoints and accessibility — to create a pleasant navigation experience. It can get more challenging in frontend frameworks like React, where CSS-in-JS tends to get tricky.
In this tutorial, we will learn about creating a responsive navigation bar using React and CSS. Also, we will be taking a look at how we can use the useMediaQuery
Hook to make our navbar responsive to different screen sizes. The final result will look and behave as shown below:
You can fiddle with the source code and view the live project here.
To follow along with this tutorial, you’ll need:
Now, let’s set up a new React application!
To get started, we will bootstrap a new React project using the following command:
npx create-react-app navigation-bar
This will create a new React project with starter files for us to start our implementation. Next up, we will install the necessary dependencies like so:
npm install react-router-dom@6 react-icons react-responsive
We’re using React Router DOM for dynamic routing as we build our feature. Since we will be building a single-page application, React Router DOM allows us to navigate between different pages without loading the entire page. This makes navigation between pages fast and user-friendly.
Meanwhile, the React Icons library will provide us with the icons we need for this build. Lastly, we installed the react-responsive library, from which we’ll get our useMediaQuery
Hook.
Let’s create the necessary folders and default styling for creating our responsive navigation bar in React. To start with, we will define our default CSS custom props using CSS variables. These will serve as our global styles, which we can apply anywhere in the application:
index.css @import url("https://fonts.googleapis.com/css2?family=Dancing+Script:wght@700&family=Montserrat:wght@400;600;700&display=swap"); * { box-sizing: border-box; padding: 0; margin: 0; } :root { --header-height: 3.5rem; --first-color: hsl(28, 88%, 62%); --title-color: hsl(0, 0%, 95%); --text-color: hsl(0, 0%, 75%); --body-color: hsl(0, 0%, 6%); --body-font: "Montserrat", sans-serif; --second-font: "Dancing Script", cursive; --h2-font-size: 1.25rem; --small-font-size: 0.813rem; --font-semi-bold: 600; --z-tooltip: 10; --z-fixed: 100; } body { background-color: var(--body-color); color: var(--text-color); font-family: var(--body-font); } ul { list-style: none; } a { text-decoration: none; }
Here, we define the Google fonts that we’ll use in the entire application: Dancing Script and Montserrat. Declaring the variables in our :root
makes them available globally throughout the entire document.
Next up, we’ll create a component folder with two files: Navbar.js
and Navbar.css
. Then, we’ll create another folder called pages
where the file for the pages will reside.
Inside the App.js
file that serves as the root component for our application, we handle the routing and navigation between components without reloading the page. We use BrowserRouter
from React Router DOM to wrap the entire application’s routing system:
App.js import React from "react"; import "./App.css"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Navbar from "./Navbar/Navbar"; import Home from "./pages/Home"; import News from "./pages/News"; const App = () => { return ( <Router> <Navbar /> <main className="main-content"> <Routes> <Route path="/" element={<Home />} /> <Route path="/news" element={<News />} /> {/* Define other routes that you need*/} </Routes> </main> </Router> ); }; export default App;
Here, we are bootstrapping our app’s routing and navigation using React Router DOM. We also imported the Navbar
component and then defined the Routes
, which are components created in the pages
folder — in this case, Home.js
, News.js
, and any other routes you may need.
Routes
is a container for a nested tree of <Route>
elements that each renders the branch that best matches the current location. <Route>
declares an element that should be rendered at a certain URL path.
Navbar
componentRemember, our goal is to create a responsive navbar that initially displays the nav menu — ul
element — in a horizontal layout. On reaching a mobile viewport size, the menu repositions under the navbar and spans the remaining height and width of the screen.
Now, let’s build our Navbar
component:
Navbar.js import React, { useState } from "react"; import { NavLink } from "react-router-dom"; import { IoClose, IoMenu } from "react-icons/io5"; import "./Navbar.css"; const Navbar = () => { return ( <header className="header"> <nav className="nav container"> <NavLink to="/" className="nav__logo"> Navigation Bar </NavLink> <div className={"nav__menu"} id="nav-menu" > <ul className="nav__list"> <li className="nav__item"> <NavLink to="/" className="nav__link"> Home </NavLink> </li> <li className="nav__item"> <NavLink to="/news" className="nav__link"> News </NavLink> </li> <li className="nav__item"> <NavLink to="/about-us" className="nav__link" > About Us </NavLink> </li> <li className="nav__item"> <NavLink to="/favorite" className="nav__link" > Favorite </NavLink> </li> <li className="nav__item"> <NavLink to="/location" className="nav__link" > Location </NavLink> </li> <li className="nav__item"> <NavLink to="/get-started" className="nav__link nav__cta"> Get Started </NavLink> </li> </ul> <div className="nav__close" id="nav-close"> <IoClose /> </div> </div> <div className="nav__toggle" id="nav-toggle"> <IoMenu /> </div> </nav> </header> ); }; export default Navbar;
Here, we are declaring the Navbar
component, which has a <nav>
element wrapping the entire component. We use the <ul>
element to wrap the list of five NavLinks
that our Navbar
should contain, which route to different pages when the user clicks on them: Home, News, About Us, Favorite, and Location.
There is also a call-to-action button that leads to a Get Started page. Lastly, we are using the IoMenu
and IoClose
icons to implement the hamburger menu and the close icon for mobile views.
Finally, let’s proceed to style this component:
Navbar.css .header { position: fixed; width: 100%; top: 0; left: 0; background-color: transparent; z-index: var(--z-fixed); } .nav { display: flex; align-items: center; justify-content: space-between; position: relative; height: var(--header-height); margin: 1rem; } .nav__logo { color: var(--first-color); transition: color 0.4s; font-size: var(--h2-font-size); font-family: var(--second-font); } .nav__toggle, .nav__close { font-size: 1.5rem; color: var(--title-color); cursor: pointer; } .nav__cta { background-color: var(--first-color); color: var(--title-color); border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.3s ease; padding: 0.75rem 1.5rem; } .nav__list { display: flex; flex-direction: column; row-gap: 2.5rem; } .nav__link { color: var(--title-color); font-weight: var(--font-semi-bold); transition: color 0.4s; } .nav__link:hover { color: var(--first-color); } .nav__close { position: absolute; top: 1rem; right: 1.5rem; } .show-menu { right: 0; }
In the markup above, we use a z-index
CSS property to fix our navbar at the top of the viewport. With Flexbox, we lay out and align our navigation items. We also style the navbar and its elements, including a transparent background, various colors, transitions for hover effects, and positioning.
At this point, our navbar project’s desktop view should look like this:
You may also notice some responsive design elements in our code. Let’s talk more about making our React navbar responsive in the next section.
Now that we have defined the structure of the Navbar
component, we can start making it responsive using a media query.
Media queries are a CSS feature that lets you specify how your content layout will respond to different conditions — such as a change in viewport width.
Queries are written using the @media
rule, followed by the target media type and the breakpoint at which to apply the styles:
@media screen and (max-width: 768px) { // rules go here }
In the example above, max-width: 768px
ensures the styles are implemented only when the device width is 768px
or lower.
Let’s apply a @media
rule to our Navbar
:
Navbar.css @media screen and (max-width: 1150px) { .nav__menu { position: fixed; top: 0; right: -100%; background-color: hsla(0, 0%, 6%, 0.2); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); width: 80%; height: 100%; padding: 6rem 3rem 0; transition: right 0.4s; } }
The code above establishes that when the screen width is 1150px
or below, we display the hamburger menu and show the navigation bar. Here’s how our mobile view should look so far with the navigation menu closed:
And here’s how it should look with the menu open:
Let’s also write a rule so that when the screen width is 1150px
or above, we don’t display the hamburger menu or the close button, but instead show the navbar content in the web or desktop view that we saw earlier:
@media screen and (min-width: 1150px) { .nav { height: calc(var(--header-height) + 1rem); } .nav__toggle, .nav__close { display: none; } .nav__list { flex-direction: row; column-gap: 2.5rem; } }
Now, in the Navbar.js
file, let’s manage the showing and hiding of the navigation bar.
We’ll define a state and set showMenu
to false
, which we will use to show and hide the navigation menu on mobile. When showMenu
is true
, we apply the .show-menu
class to display the navbar.
Then, we’ll create a toggleMenu
function to handle the behavior of the navigation menu. On mobile viewports, clicking the hamburger menu icon will show the menu using the toggleMenu
function. Likewise, clicking the close icon will hide the navigation menu with the toggleMenu
function.
Additionally, we will create a closeOnMobile
function, which will only apply to the navigation links. When mobile users open the navigation menu via the hamburger icon and then click on any of the navigation links, the app will navigate the user to the selected page and close the navigation menu automatically.
Here is the updated Navbar.js
file that manages the navigation bar toggle state with a useState
Hook and the toggleMenu
function:
import React, { useState } from "react"; import { NavLink } from "react-router-dom"; import { IoClose, IoMenu } from "react-icons/io5"; import "./Navbar.css"; const Navbar = () => { const [showMenu, setShowMenu] = useState(false); const toggleMenu = () => { setShowMenu(!showMenu); }; const closeMenuOnMobile = () => { if (window.innerWidth <= 1150) { setShowMenu(false); } }; return ( <header className="header"> <nav className="nav container"> <NavLink to="/" className="nav__logo"> Navigation Bar </NavLink> <div className={`nav__menu ${showMenu ? "show-menu" : ""}`} id="nav-menu" > <ul className="nav__list"> <li className="nav__item"> <NavLink to="/" className="nav__link" onClick={closeMenuOnMobile}> Home </NavLink> </li> <li className="nav__item"> <NavLink to="/news" className="nav__link" onClick={closeMenuOnMobile}> News </NavLink> </li> <li className="nav__item"> <NavLink to="/about-us" className="nav__link" onClick={closeMenuOnMobile} > About Us </NavLink> </li> <li className="nav__item"> <NavLink to="/favorite" className="nav__link" onClick={closeMenuOnMobile} > Favorite </NavLink> </li> <li className="nav__item"> <NavLink to="/location" className="nav__link" onClick={closeMenuOnMobile} > Location </NavLink> </li> <li className="nav__item"> <NavLink to="/get-started" className="nav__link nav__cta"> Get Started </NavLink> </li> </ul> <div className="nav__close" id="nav-close" onClick={toggleMenu}> <IoClose /> </div> </div> <div className="nav__toggle" id="nav-toggle" onClick={toggleMenu}> <IoMenu /> </div> </nav> </header> ); }; export default Navbar;
Let’s see what we have now on the UI:
useMediaQuery
to handle responsivenessThe useMediaQuery
React Hook allows us to use CSS media queries inside components to render JSX conditionally based on the specified screen size. It’s very useful for creating responsive designs in React applications.
Let’s see how we can apply the Hook to make our navbar responsive by refactoring what we have in the Navbar.js
file. In the Navbar.css
file, we will remove the media query part since we are handling the responsiveness with the useMediaQuery
Hook.
To start, we will import the useMediaQuery
Hook from the react-responsive package and maintain the showMenu
state to handle mobile-view navigation. The navigation menu will be rendered conditionally based on the specified screen size:
import React, { useState } from "react"; import { NavLink } from "react-router-dom"; import { IoClose, IoMenu } from "react-icons/io5"; import { useMediaQuery } from "react-responsive"; import "./NavbarMobile.css"; const NavbarHook = () => { const [isMenuOpen, setIsMenuOpen] = useState(false); const isMobile = useMediaQuery({ maxWidth: "1150px" }); const toggleMenu = () => { setIsMenuOpen(!isMenuOpen); }; const closeMobileMenu = () => { if (isMobile) { setIsMenuOpen(false); } }; const renderNavLinks = () => { const listClassName = isMobile ? "nav__list" : "nav__list__web"; const linkClassName = "nav__link"; const buttonClassName = "nav__cta"; return ( <ul className={listClassName}> <li> <NavLink to="/" className={linkClassName} onClick={closeMobileMenu}> Home </NavLink> </li> <li> <NavLink to="/news" className={linkClassName} onClick={closeMobileMenu} > News </NavLink> </li> <li> <NavLink to="/about-us" className={linkClassName} onClick={closeMobileMenu} > About Us </NavLink> </li> <li> <NavLink to="/favorite" className={linkClassName} onClick={closeMobileMenu} > Favorite </NavLink> </li> <li> <NavLink to="/location" className={linkClassName} onClick={closeMobileMenu} > Location </NavLink> </li> <li> <NavLink to="/get-started" className={`${linkClassName} ${buttonClassName}`} onClick={closeMobileMenu} > Get Started </NavLink> </li> </ul> ); }; return ( <header className="header"> <nav className="nav container"> <NavLink to="/" className="nav__logo"> Navigation Bar </NavLink> {isMobile && ( <div className="nav__toggle" id="nav-toggle" onClick={toggleMenu}> <IoMenu /> </div> )} {isMobile ? ( <div className={`nav__menu ${isMenuOpen ? "show-menu" : ""}`} id="nav-menu" > {renderNavLinks()} <div className="nav__close" id="nav-close" onClick={toggleMenu}> <IoClose /> </div> </div> ) : ( renderNavLinks() )} </nav> </header> ); }; export default NavbarHook;
Here, we defined the screen‘s responsive breakpoint as 1150px
. Then, we display the menu and close icons only if the isMobile
variable value is true
— in other words, once the screen size is less than 1150px
, we show these two buttons.
With that complete, you can check out the CSS file for this implementation. Also, don’t forget to import the NavbarHook.js
file inside the App.js
file to render the implementation and see how it looks on the user interface.
The final result is when the screen’s size is higher than 1150px
— in other words, a web or desktop view screen size — we display the navbar and its nav link content horizontally. However, if the isMobile
value is 1150px
or less, we display the mobile view for the navbar.
Navigation menus serve an important role in the overall experience of your web application. It’s usually the first component your user encounters when trying to figure out your app. Making your navbar as organized and accessible as possible can help boost UX and even SEO performance.
You can check out the final project here and the source code here. If you have any questions, feel free to comment below.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
7 Replies to "Create a responsive navbar with React and CSS"
great article!
Thanks!
thanks bro
this was very useful, thank you
This helps
Any form controls on page are not overlapped by the menu in mobile view. Can you help?
where is the list of variables ??