React bootstrap side navbar – How to Create a Navigation Bar and Sidebar Using React

INTRODUCTION

React bootstrap side navbar: The navbar I focus on will be a sidebar via React. I will guide you through the React project creation. Make sure you have node.js installed in your system.

  1. Make a workspace folder and name it.
  2. Use npx create-react-app navbar to create a new project in the directory.
  3. Navigate inside it by using cd navbar in your IDE, I would recommend using Visual Studio Code.
  4. npm start in terminal to start the localhost server in your browser, I would recommend using Google Chrome.

 

DEPENDENCIES REQUIRED

React sidebar navigation: Go into package.json file and paste these dependencies in there:

"bootstrap": "^4.3.1",
"react": "^16.10.2",
"react-bootstrap": "^1.0.0-beta.14",
"react-dom": "^16.10.2",
"react-router-dom": "^5.0.1",
"react-scripts": "3.1.1",
"styled-components": "^4.3.2"

Now actually install these dependencies by opening a terminal and typing:

npm install

Paste this CDN link in the <head> tag inside index.html. It is for Font Awesome icons.

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

 

MAKING COMPONENT STRUCTURE

React menu bar: Right click on the src folder and create a folder called components.

Right click on the components folder and create a Navbar.js file. Paste the code written below.

import React from "react";

export const NavigationBar = () => (
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
      <a class="navbar-brand" href="#">
        Navbar
      </a>
      <button
        class="navbar-toggler"
        type="button"
        data-bs-toggle="collapse"
        data-bs-target="#navbarSupportedContent"
        aria-controls="navbarSupportedContent"
        aria-expanded="false"
        aria-label="Toggle navigation"
      >
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#">
              Home
            </a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">
              Link
            </a>
          </li>
          <li class="nav-item dropdown">
            <a
              class="nav-link dropdown-toggle"
              href="#"
              id="navbarDropdown"
              role="button"
              data-bs-toggle="dropdown"
              aria-expanded="false"
            >
              Dropdown
            </a>
          </li>
          <li class="nav-item">
            <a
              class="nav-link disabled"
              href="#"
              tabindex="-1"
              aria-disabled="true"
            >
              Disabled
            </a>
          </li>
        </ul>
        <form class="d-flex">
          <input
            class="form-control me-2"
            type="search"
            placeholder="Search"
            aria-label="Search"
          />
          <button class="btn btn-outline-success" type="submit">
            Search
          </button>
        </form>
      </div>
    </div>
  </nav>
);

Now the header will look similar to the picture mentioned below.

Routing is how you get from page to page, so paste the code below inside <Router>. It basically says, if on this path, render this particular component:

<Switch>
  <Route exact path="/" component={Home} />
  <Route path="/about" component={About} />
  <Route component={NoMatch} />
</Switch>

This currently breaks the app because we do not have these components. So, let’s add these pages to make sure navigation will work.

Inside of src/components/Pages, create Home.js and paste this inside:

import React from "react";
import styled from "styled-components";
const GridWrapper = styled.div`
  display: grid;
  grid-gap: 10px;
  margin-top: 1em;
  margin-left: 6em;
  margin-right: 6em;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: minmax(25px, auto);
`;
export const Home = (props) => (
  <GridWrapper>
    <p>This is a paragraph and I am writing on the home page</p>
    <p>This is another paragraph, hi hey hello whatsup yo</p>
  </GridWrapper>
);

Inside of src/components/Pages, create About.js and paste this inside:

import React from "react";
import styled from "styled-components";
const GridWrapper = styled.div`
  display: grid;
  grid-gap: 10px;
  margin-top: 1em;
  margin-left: 6em;
  margin-right: 6em;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: minmax(25px, auto);
`;
export const About = () => (
  <GridWrapper>
    <h2>About Page</h2>
    <p>
      State at ceiling lay on arms while you're using the keyboard so this human
      feeds me.
    </p>
    <p>I am a kitty cat, sup, feed me, no cares in the world</p>
    <p>Meow meow, I tell my human purr for no reason but to chase after</p>
  </GridWrapper>
);

Inside of src/components/Pages, create Nomatch.js and paste this inside:

import React from 'react';
import styled from 'styled-components';
const Wrapper = styled.div`
  margin-top: 1em;
  margin-left: 6em;
  margin-right: 6em;
`;
export const NoMatch = () => (
  <Wrapper>
    <h2>No Match</h2>
  </Wrapper>
)

Do not forget to include the components in App.js file.

import { Home } from "./components/Pages/Home";
import { About } from "./components/Pages/About";
import { Nomatch } from "./components/Pages/Nomatch";

Alright, we can actually create the sidebar now.

Inside of components, create Sidebar.js

We know that we want to create a Sidebar component and export it for use inside of App.js. Put this inside Sidebar.js:

import React, { Component } from 'react'

export class Sidebar extends Component {
    render() {
        return (
            <div>
                
            </div>  
        )
    }
}

export default Sidebar

This basically is a class component, which renders a given code.

Then paste the code given below inside the return statement.

<SideNav></SideNav>

Now creating all the components required in separate files namely,  SideNav.js and NavItem.js.

NavItem.js

class NavItem extends React.Component {
  render() {
    return (
    );
  }
}

Inside of render, but above return, type:

const { active } = this.props;

This gets the active variable out of NavItem’s props. Now import the following

import { BrowserRouter as Router, Route, Link } from "react-router-dom";

Inside NavItem’s return, add this:

<StyledNavItem active={active}>
  <Link to={this.props.path} className={this.props.css} onClick={this.handleClick}>
    <NavIcon></NavIcon>
  </Link>
</StyledNavItem>

If you look at the props on <Link>, to is the path to go to, className passes in the CSS for the Font Awesome icon, and onClick will call the handleClick() method. Let’s create that method. Put it above render:

handleClick = () => {
  const { path, onItemClick } = this.props;
  onItemClick(path);
}

This arrow function gets path and onItemClick from NavItem’s props and then calls onItemClick().

Create StyledNavItem. The <Link> tag uses an anchor, so, the anchor selector is used. The only confusing part about the CSS is the part that uses props. It says: using the active prop, decide which of the colors to choose. So, if the home page is active, make the home page icon white:

const StyledNavItem = styled.div`
  height: 70px;
  width: 75px; /* width must be same size as NavBar to center */
  text-align: center; /* Aligns <a> inside of NavIcon div */
  margin-bottom: 0;   /* Puts space between NavItems */
  a {
    font-size: 2.7em;
    color: ${(props) => props.active ? "white" : "#9FFFCB"};
    :hover {
      opacity: 0.7;
      text-decoration: none; /* Gets rid of underlining of icons */
    }  
  }
`;

 

 

 

SideNav.js

Styled components used for styling the sidenav component.

const StyledSideNav = styled.div`
  position: fixed; /* Fixed Sidebar (stay in place on scroll and position relative to viewport) */
  height: 100%;
  width: 75px; /* Set the width of the sidebar */
  z-index: 1; /* Stay on top of everything */
  top: 3.4em; /* Stay at the top */
  background-color: #222; /* Black */
  overflow-x: hidden; /* Disable horizontal scroll */
  padding-top: 10px;
`;

We want SideNav to be a stateful component. This is because it needs to store what the current path is and based on that decide which icon should be selected and colored white.

Create a constructor. In there, create a state that holds the activePath, which we will set to the home path for now, and items that holds the information for our selectable icons

constructor(props) {
  super(props);
  this.state = {
    activePath: '/',
    items: [
      {
        path: '/', 
        name: 'Home',
        css: 'fa fa-fw fa-home',
        key: 1 
      },
      {
        path: '/about',
        name: 'About',
        css: 'fa fa-fw fa-clock',
        key: 2
      },
      {
        path: '/NoMatch',
        name: 'NoMatch',
        css: 'fas fa-hashtag',
        key: 3
      },
    ]
  }  
}
onItemClick = (path) => {
  this.setState({ activePath: path }); /* Sets activePath which causes rerender which causes CSS to change */
}

All this code says is change the activePath by setting the state. If you do not know, whenever you call setState(), React will rerender your component, which will render the change to show you selected a different icon.

Change your render to look like this:

render() {
  const { items, activePath } = this.state;
  return (
    <StyledSideNav>
      {
        /* items = just array AND map() loops thru that array AND item is param of that loop */
        items.map((item) => {
          /* Return however many NavItems in array to be rendered */
          return (
            <NavItem path={item.path} name={item.name} css={item.css} onItemClick={this.onItemClick} /* Simply passed an entire function to onClick prop */ active={item.path === activePath} key={item.key}/>
          )
        })
      }
    </StyledSideNav>
  );
}

Before return, items and activePath are retrieved from the state. In order to render out all NavItems, we loop through all of the items using map().

 

NOTE: Remember to import all required imports that are used in the files, specially the custom HTML tags.