jvzznjs
jvzznjs

Reputation: 61

React responsive navbar and hamburger menu

I need to make React responsive navbar. I find some that work in HTML, but not in React. I think problem is in getElementById, because React doesn't support it.

import React from "react";
import { Link } from "react-router-dom";
import "./index.css";

function myFunction() {
  var x = document.getElementById("myTopnav");
  if (x.className === "topnav") {
    x.className += " responsive";
  } else {
    x.className = "topnav";
  }
}
function Header() {
  return (
    <nav>
      <div className="topnav" id="myTopnav">
        <a href="#home" className="active">
          Home
        </a>
        <a href="#news">News</a>
        <a href="#contact">Contact</a>
        <a href="#about">About</a>
        <a href="javascript:void(0);" className="icon" onclick={myFunction}>
          <i className="fa fa-bars"></i>
        </a>
      </div>
    </nav>
  );
}

export default Header;

This is the CSS my project is using:

.topnav {
  overflow: hidden;
  background-color: black;
}

.topnav a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
  font-size: 17px;
}

.topnav a:hover {
  background-color: #ddd;
  color: black;
}

.topnav .icon {
  display: none;
}

@media screen and (max-width: 600px) {
  .topnav a {
    display: none;
  }
  .topnav a.icon {
    float: right;
    display: block;
  }
}

@media screen and (max-width: 600px) {
  .topnav.responsive {
    position: relative;
  }
  .topnav.responsive .icon {
    position: absolute;
    right: 0;
    top: 0;
  }
  .topnav.responsive a {
    float: none;
    display: block;
    text-align: left;
  }
}

How should I update my react code so that the responsive menu appears when clicking the icon?

Upvotes: 3

Views: 3269

Answers (2)

jymbob
jymbob

Reputation: 488

You'll probably have fewer problems down the line if you add a useState hook to manage your component, rather than using javascript to modify the DOM directly.

import React, { useState } from 'react';

const Header = () => {
  // set a variable 'responsive' to false. Update it using 'setResponsive'
  const [responsive, setResponsive] = useState(false);

  const toggleResponsive = () => {
    //take current value of responsive and flip it
    setResponsive(prev => !prev);
  }

  return (
    <nav>
      <div className={responsive ? 'topnav responsive' : 'topnav'}>
        <a href='#home'>Home</a>
        ...
        <a className='icon' onClick={toggleResponsive}>
          <i className="fa fa-bars"></i>
        </a>
      </div>
    </nav>
  );
}

Upvotes: 1

Rashed Rahat
Rashed Rahat

Reputation: 2495

Updated

Place myFunction() inside Header() as this is a Functional based component.

Here is the Header component looks like after changes:

import React from "react";
import { Link } from "react-router-dom";
import "./index.css";

function Header() {
  const myFunction = () => {
    var x = document.getElementById("myTopnav");
    if (x.className === "topnav") {
      x.className += " responsive";
    } else {
      x.className = "topnav";
    }
  }

  return (
    <nav>
      <div className="topnav" id="myTopnav">
        <a href="#home" className="active">
          Home
        </a>
        <a href="#news">News</a>
        <a href="#contact">Contact</a>
        <a href="#about">About</a>
        <a href="javascript:void(0);" className="icon" onClick={myFunction}>
          <i className="fa fa-bars"></i>
        </a>
      </div>
    </nav>
  );
}

export default Header;

Please visit this link to see: Code Sandbox Live Demo

Upvotes: 2

Related Questions