Home > Software engineering >  How to add a class on click, and remove the same class from all other elements?
How to add a class on click, and remove the same class from all other elements?

Time:11-28

I have a button navigation and when you click on a button, the active class is added. My goal is for the active class to be added to the button clicked, but remove that class of active on all other buttons if present. The 'About' button will have a class of active on page load.

Not sure how to translate this to React, in JavaScript on click I would remove the class from all the elements in a loop and add a class to the target clicked if it did not already have the active class.

Code Sandbox - https://codesandbox.io/s/toggle-active-on-class-clicked-remove-from-the-rest-r467l1?file=/src/App.js

export default function Header() {
  const [active, setActive] = useState(true);

  const toggleColor = function (e) {
    // on load, 'About' button has active class
    // when clicking another menu item add active class, remove active from the rest of buttons
    console.log(e.target);
  };

  return (
    <header className="header-img-container">
      <nav>
        <ul>
          <li>
            <button onClick={toggleColor} className={active ? "active" : ""}>
              About
            </button>
          </li>
          <li>
            <button onClick={toggleColor}>Skills</button>
          </li>
          <li>
            <button onClick={toggleColor}>Projects</button>
          </li>
          <li>
            <button onClick={toggleColor}>Words</button>
          </li>
        </ul>
      </nav>
    </header>
  );
}

CodePudding user response:

There are so many ways to solve that problem. You can try this if it's meet your requirements.

import "./styles.css";

import { useState } from "react";

const list = ["About", "Skills", "Projects", "Words"];

export default function Header() {
  const [activeLink, setActiveLink] = useState("About");

  return (
    <header className="header-img-container">
      <nav>
        <ul>
          {list.map((item) => (
            <li key={item}>
              <button
                onClick={() => setActiveLink(item)}
                className={activeLink === item ? "active" : ""}
              >
                {item}
              </button>
            </li>
          ))}
        </ul>
      </nav>
    </header>
  );
}

CodePudding user response:

Create a state like this

const [active, setActive] = useState({About: true, Skills: false, Projects: false, Words: false})

А change local parameter to add a class to element. For example

<li>
  <button onClick={() => {
    setActive({...active, About: false, Skills: true, Projects: false, 
    Words: false })
    }}>Skills</button>
</li>

CodePudding user response:

There are many possible approaches, here is a basic example that uses an object type active state to store the value for each list item.

const [active, setActive] = useState({ About: true })

The list data is stored in an array so it can be mapped in the JSX part of the component.

const itemList = ["About", "Skills", "Projects", "Words"]

While index is not an ideal key it is used here just for example purpose.

{
  itemList.map((item, index) => (
    <li key={index}>
      <button
        onClick={() => toggleColor(item)}
        className={active[item] ? "active" : ""}
      >
        {item}
      </button>
    </li>
  ));
}

toggleColor sets value for active, and it specify that active should always be in the format of {About: true}, {Skills: true} and such. The !!! covers the case when certain keys are not existing in the object.

const toggleColor = function (item) {
  setActive((prev) => {
    return { [item]: !!!prev[item] };
  });
};

Below is the full example, it runs in the snippet for convenience.

function Header() {
  const [active, setActive] = React.useState({ About: true });

  const itemList = ["About", "Skills", "Projects", "Words"];

  const toggleColor = function (item) {
    // on load, 'About' button has active class
    // when clicking another menu item add active class, remove active from the rest of buttons
    setActive((prev) => {
      return { [item]: !!!prev[item] };
    });
  };

  return (
    <header className="header-img-container">
      <nav>
        <ul>
          {itemList.map((item, index) => (
            <li key={index}>
              <button
                onClick={() => toggleColor(item)}
                className={active[item] ? "active" : ""}
              >
                {item}
              </button>
            </li>
          ))}
        </ul>
      </nav>
    </header>
  );
}

const App = () => {
  return (
    <div>
      <Header />
    </div>
  );
};

ReactDOM.render(<App />, document.querySelector("#root"));
.App {
  font-family: sans-serif;
  text-align: center;
}

button {
  padding: 6px;
}

.active {
  border: 1px solid pink;
  color: hotpink;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

  • Related