Adewale Perfect
Adewale Perfect

Reputation: 573

How to toggle CSS styles with Toggle method in React

This is Header component with React-Bootstrap. I created a menu icon with pure CSS but I want to change the icon function onClick but I'm getting the error - TypeError: Cannot read property 'toggle' of undefined . It's there any way I'm getting it wrongly? Kindly check. Thanks.

Also, it's there a way, I can handle this with React Hooks method instead?

Thanks.

import styles from './Landing.module.css';
import './Landing.module.css';;

const openMenu = (open) => {
    open.classList.toggle('change');
};

 <Nav className="ml-auto">
  <div className={styles.allMenus}>
    <div className="menuIcon" onClick={openMenu}>
       <div className={styles.bar1}></div>
         <div className={styles.bar2}></div>
           <div className={styles.bar3}></div>
         </div>
      </div>
 </Nav>

My CSS - It has the change styles

div[class="menuIcon"] {
    background-color: #ffffff;
    padding: 13px;
    margin-right: 46px;
    float: right;
    cursor: pointer;
}

.bar1, .bar2, .bar3 {
    width: 32px;
    height: 3px;
    background-color: #333;
    margin: 6px 0;
    transition: 0.4s;
}

.change .bar1 {
    -webkit-transform: rotate(-45deg) translate(-9px, 6px) ;
    transform: rotate(-45deg) translate(-9px, 6px) ;
}
  
.change .bar2 {
    opacity: 0;
}
  
.change .bar3 {
    -webkit-transform: rotate(45deg) translate(-8px, -8px) ;
    transform: rotate(45deg) translate(-8px, -8px) ;
}

Upvotes: 1

Views: 369

Answers (1)

Ori Drori
Ori Drori

Reputation: 191976

You are trying to use the DOM's classList in React, but react JSX elements are not DOM elements, but an XML based markup that is translated to JS.

In React you'll need to use state/props to control the behaviour, and add or remove the classes.

In the example I'm using the useState() hook to toggle a boolean, and then I add or remove the class name in the template string.

You can use a library, such as classnames to prevent yourself from writing lots of template strings with class names.

const { useState } = React;

const styles = {
  menuIcon: 'menuIcon',
  change: 'change',
  bar1: 'bar1',
  bar2: 'bar2',
  bar3: 'bar3',
};

const Demo = () => {
  const [changed, setChange] = useState(false);
  
  const openMenu = (open) => {
    setChange(c => !c);
  };

  return (
    <nav className="ml-auto">
      <div className="allMenus">
        <div className={`${styles.menuIcon} ${changed ? styles.change : ''}`} onClick={openMenu}>
          <div className={styles.bar1}></div>
          <div className={styles.bar2}></div>
          <div className={styles.bar3}></div>
        </div>
      </div>
    </nav>
  );
}

ReactDOM.render(
  <Demo />,
  root
);
.menuIcon {
  padding: 13px;
  margin-right: 46px;
  float: right;
  cursor: pointer;
}

.bar1,
.bar2,
.bar3 {
  width: 32px;
  height: 3px;
  background-color: #333;
  margin: 6px 0;
  transition: 0.4s;
}

.change .bar1 {
  -webkit-transform: rotate(-45deg) translate(-9px, 6px);
  transform: rotate(-45deg) translate(-9px, 6px);
}

.change .bar2 {
  opacity: 0;
}

.change .bar3 {
  -webkit-transform: rotate(45deg) translate(-8px, -8px);
  transform: rotate(45deg) translate(-8px, -8px);
}
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

<div id="root"></div>

Upvotes: 1

Related Questions