No Time Dad

A blog about web development written by a busy dad

A Simple React Navbar

I was recently tasked with creating a react navbar component. One of the main requirements was reusability. Each section of the navbar needed to take different values based on the navbar’s location in the application and the state of the application. For example, if a user was logged in it should show a logout button or a settings button. Conversely, if a user wasn’t logged in it should show a login or signup button and no settings button.

These are common requirements for a navbar. And I’ve made many react navbar components like this in the past. The key is to keep it simple and not make too many assumptions up front about the look and feel of the navbar. I’ve found that it’s better to let the props being passed to the navbar decide all of these things. So really what I’m creating is a navbar template.

When making a navigation element, or really any kind of html element, I think it’s important to try and use semantic html as much as possible. Doing so makes the code easier to read for anyone working on it down the road. It easier to read for screen readers, which improves the accessibility of the page. There’s also SEO benefits to using semantic html.

MyApp
// navbar.jsx
import React from 'react';
import * as styles from './navbar.module.css';

export const Navbar = ({ titleIcon, titleText, rightIcon }) => (
  <header className={styles.header}>
    <div className={styles.title}>
      {titleIcon}
      <div className={styles.title_text}>
        {titleText}
      </div>
    </div>
    <div>
      {rightIcon}
    </div>
  </header>
);

export const FireSvg = () => (
  <svg xmlns="http://www.w3.org/2000/svg" className={styles.header_icon} viewBox="0 0 20 20" fill="currentColor">
    <path fillRule="evenodd" d="M12.395 2.553a1 1 0 00-1.45-.385c-.345.23-.614.558-.822.88-.214.33-.403.713-.57 1.116-.334.804-.614 1.768-.84 2.734a31.365 31.365 0 00-.613 3.58 2.64 2.64 0 01-.945-1.067c-.328-.68-.398-1.534-.398-2.654A1 1 0 005.05 6.05 6.981 6.981 0 003 11a7 7 0 1011.95-4.95c-.592-.591-.98-.985-1.348-1.467-.363-.476-.724-1.063-1.207-2.03zM12.12 15.12A3 3 0 017 13s.879.5 2.5.5c0-1 .5-4 1.25-4.5.5 1 .786 1.293 1.371 1.879A2.99 2.99 0 0113 13a2.99 2.99 0 01-.879 2.121z" clipRule="evenodd" />
  </svg>
);

export const CogSvg = () => (
  <svg xmlns="http://www.w3.org/2000/svg" className={styles.header_icon} viewBox="0 0 20 20" fill="currentColor">
    <path fillRule="evenodd" d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" clipRule="evenodd" />
  </svg>
);
/* navbar.module.css */
.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: lightcyan;
  padding: 1rem;
}

.title {
  display: flex;
  align-items: center;
}

.header_icon {
  height: 2.5rem;
  width: 2.5rem;
}

.title_text {
  font-size: 22px;
  font-weight: 600;
  margin-left: 0.25rem;
}

There are a few things I really like about this design. I know it’s simple, but it’s meant to be built on. It lends itself to being built on by allowing “sections” of the react navbar to be passed as props. You can pass just plain text as I’ve done above, or pass an entire component that has it’s own styles applied. That’s what makes this component design so flexible. It’s really just scaffolding.

It’s easy to go overboard with props, though. I’ve fallen into this trap many times. I’ll start slicing and dicing my components into sections and before I know it I’m passing over six different props down into a single div, which doesn’t make much sense. It’s better to take a more calculated approach and try to keep the number of props to under five. This’ll keep the code clean and easier to understand. It’ll also be easier to write tests for the component. When I start noticing a lot of props in my react component I know it’s time to think about breaking it up into multiple components.

Flexbox is the hero of this navbar component. It takes care of most of the alignment and spacing. I didn’t have to calculate anything or worry about vertical padding to get the icon and text centered. I just had to use align-items: center; and it’s done. The other nice thing flexbox is doing in this component is pushing the second (cog) icon all the way to the right. This is done via justify-content: space-between;. And it works because there are only two elements in the flexbox container.

If there were three (or more) elements this would break. I’d have one element on the left, one element in the center, and one element on the right. This can be desirable though, if I wanted to have a section in the middle containing nav links. The spacing would be taken care of for me by flexbox.

A quick word about using third party libraries for creating a react navbar. If a given project is already using a library like Bootstrap or Material then absolutely look in their documentation to see if they’ve provided a navbar to use. There’s not really a good reason to re-invent the wheel here. However, I’m always a big advocate of writing your own css. So, if there isn’t a pre-made solution at hand, I’d always recommend building it. Even just for the purpose of practice. Actually, especially for the purpose of practice.