Search code examples
cssstenciljs

Change CSS class on click in Stenciljs


Is it possible to use the simple menu animation from W3School in Stencil.js?

https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_menu_icon_js

I'm trying to set the styling on a click event, but I can't make it work. The event is fireing but I can't set the class.

In my .tsx:

import { Component, Prop, h } from '@stencil/core';

@Component({
  tag: 'topbar-component',
  styleUrl: 'topbar-component.css',
  shadow: true
})

export class Topbar {

  private menuToggle(e) {
    return (
      e.classList.toggle("change");
    );
  }

  render() {
    return (
      <div class="topbar-menu">
        <div class="container" onClick={(e) => this.menuToggle(e)}>
            <div class="bar1"></div>
            <div class="bar2"></div>
            <div class="bar3"></div>
        </div>
      </div>
    )
  }
}

In my css:

.bar1, .bar2, .bar3 {
  width: 35px;
  height: 5px;
  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);
}

I get error: Uncaught TypeError: Cannot read property 'toggle' of undefined


Solution

  • You could do it using a state property:

    import { Component, Prop, State, h } from '@stencil/core';
    
    @Component({
      tag: 'topbar-component',
      styleUrl: 'topbar-component.css',
      shadow: true
    })
    
    export class Topbar {
    
      @State() isMenuOpen: boolean = false;
    
      private menuToggle() {
        this.isMenuOpen = !this.isMenuOpen;
      }
    
      render() {
        return (
          <div class="topbar-menu">
            <div class={{ container: true, change: this.isMenuOpen }}" onClick={(e) => this.menuToggle(e)}>
                <div class="bar1"></div>
                <div class="bar2"></div>
                <div class="bar3"></div>
            </div>
          </div>
        )
      }
    }