Search code examples
javascriptcssreactjscss-modulesreact-css-modules

Button doesn't work if I use template literals to toggle CSS classes in React


I have a CSS module called styles and this React code. It's a div with two buttons inside. I use the isMenuActive state to verify if the menu is active or not. If it is active, the CSS class 'active' gets in and the menu appears, otherwise not.

  <div className={`${styles.customerOptionsMenu} ${isMenuActive ? styles.active : null}`}>
    <button onClick={() => { console.log('hi') }}>
      <span className="material-icons">edit</span>Editar
    </button>
    <button onClick={() => {console.log('hi')}}>
      <span className="material-icons">delete</span>Deletar
    </button>
  </div>

When I click the buttons, nothing happens.

But If I store the button as a global variable in developer tools and run button.click() it works fine if I remove the template literals:

  <div className={styles.customerOptionsMenu + styles.active}>
    <button onClick={() => { console.log('hi') }}>
      <span className="material-icons">edit</span>Editar
    </button>
    <button onClick={() => {console.log('hi')}}>
      <span className="material-icons">delete</span>Deletar
    </button>
  </div>

It works fine.

Why??? And what should I do to keep changing the classes when isMenuActive changes?

Edit: Full code with the button that changes isMenuActive

  const [isMenuActive, setIsMenuActive] = useState(false)
  const onBlur = () => { setIsMenuActive(!isMenuActive)}

  return(
    <td>
      <button onBlur={onBlur} className={styles.customerOptions} onClick={() => setIsMenuActive(!isMenuActive)}>
        <span className="material-icons">more_horiz</span>
      </button>
      <div className={`${styles.customerOptionsMenu} ${isMenuActive ? styles.active : null}`}>
        <button onClick={() => { console.log('hi') }}>
          <span className="material-icons">edit</span>Editar
        </button>
        <button onClick={() => {console.log('hi')}}>
          <span className="material-icons">delete</span>Deletar
        </button>
      </div>
    </td>
  )

New edit: The answer is in the comments by Pandaiolo. The problem was the onBlur={onBlur} code, when I removed it from the button everything worked fine!


Solution

  • I think the space is fine in your template literal, because it references two different class names. You probably want to use ${isMenuActive ? styles.active :''} otherwise null becomes the string "null", which is probably harmless unless you have a class .null that applies some styles, but that is basically not what you want.

    But maybe the onBlur is called after the click?

    1. click
    2. button becomes focus
    3. button blurs ?

    Not sure. But in that case it would toggle the state two times, cancelling its effect. Maybe try with just the onClick and without the onBlur at first?

    And you can add a console.log('isMenuActive', isMenuActive) before the return statement to see it's value along rerenders, see if it matches what you expect.