css-animationsbulmaalpine.js

Can't seem to create a reverse animation to close the menu


I'm sure there are many people on this forum who will tell me off for making life difficult for myself by not simply using Tailwind.CSS when making anything with Alpine.JS, but the purpose of this exercise is to show that Alpine can be done with anything, and isn't restricted to one CSS framework only.

My example uses Bulma, I prefer this as I find it to be more developer-friendly than Bootstrap or Tailwind. What I've created is a personalised navigation menu and got it to slide in perfectly from the right on the click of the button, but I can't seem to create a reverse animation to close the menu. Not that I expect many users to see this animation, but it's purely for aesthetic purposes.

My "mess of a code" is below:

HTML & Alpine

<body x-data="{ isOpen: false }" x-cloak directive.>

    <div x-show="isOpen" >
        <div id="side_navbar" x-transition:enter="slide_In">

            <img id="close_icon" x-transition:enter="slide_Out" class="is-pulled-right m-4" src="close_icon.svg" width="32px" @click=" isOpen = false ">

            <ul class="side_navbar-items mx-2 my-6 pt-1">
                <li><a class="side_navbar-item mb-4">link</a></li>
                <li><a class="side_navbar-item mb-4">link</a></li>
            </ul>

        </div><!-- side_navbar -->
    </div><!-- x-show component isOpen -->

<nav class="navbar" role="navigation" aria-label="main navigation">
  <div class="navbar-brand">
    <!-- navbar items, navbar burger... -->
    <a class="navbar-item" href="#">
      <img src="Grouplogo.svg">
    </a>

    <a role="button" class="site-menu " width="32px" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample" @click=" isOpen = !isOpen">
    <img src="burger_icon.svg">
  </a>

  </div><!-- navbar-brand -->

 <div id="navbarBasicExample" class="navbar-menu">

  <div class="navbar-menu">
    <!-- navbar start, navbar end -->
    <div class="navbar-end">

        <div class="navbar-item has-text-weight-medium ">
        <a class="navbar-item">link</a>
        <a class="navbar-item">link</a>
       
    </div><!-- navbar-end -->

    </div><!-- x-show component isOpen -->

Custom CSS

#side_navbar{
    background-color: #57219C;
    color: #fffeff;
    z-index: 100;
    position: absolute;
    right: 0;
    top: 0;
    min-width: 20em;
    min-height: 100%;
    animation-name: slide_In;
    animation-duration: 0.1s;
}

@keyframes slide_In {
  from {
    margin-right: -200px;
    opacity: 0;
  }

  to {
    margin-right: 0;
    opacity: 1;
  }
}


@keyframes slide_Out {
  from {
    margin-right: 0;
  }

  to {
    margin-right: 200px;
  }
}

Feedback is always welcome


Solution

  • Since you are toggling between two states, consider using transition and having classes corresponding to each state. Furthermore, we'd need x-show on the same element as the x-transition directives so that Alpine is aware that it needs to show/hide with a transition.

    #side_navbar {
      background-color: #57219C;
      color: #fffeff;
      z-index: 100;
      position: absolute;
      right: 0;
      top: 0;
      min-width: 20em;
      min-height: 100%;
      transition: opacity 0.1s, transform 0.1s;
    }
    
    #side_navbar.out {
      transform: translateX(200px);
      opacity: 0;
    }
    
    #side_navbar.in {
      transform: translateX(0px);
      opacity: 1;
    }
    
    [x-cloak] {
      display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/2.3.0/alpine.js" integrity="sha512-nIwdJlD5/vHj23CbO2iHCXtsqzdTTx3e3uAmpTm4x2Y8xCIFyWu4cSIV8GaGe2UNVq86/1h9EgUZy7tn243qdA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.4/css/bulma.min.css" integrity="sha512-HqxHUkJM0SYcbvxUw5P60SzdOTy/QVwA1JJrvaXJv4q7lmbDZCmZaqz01UPOaQveoxfYRv1tHozWGPMcuTBuvQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    
    <body x-data="{ isOpen: false }" x-cloak directive.>
    
      <div x-show="isOpen">
        <div
          id="side_navbar"
          x-show="isOpen"
          x-transition:enter-start="out"
          x-transition:enter-end="in"
          x-transition:leave-start="in"
          x-transition:leave-end="out"
        >
    
          <img id="close_icon" x-transition:enter="slide_Out" class="is-pulled-right m-4" src="https://picsum.photos/32/32?close_icon.svg" width="32px" @click=" isOpen = false ">
    
          <ul class="side_navbar-items mx-2 my-6 pt-1">
            <li><a class="side_navbar-item mb-4">link</a></li>
            <li><a class="side_navbar-item mb-4">link</a></li>
          </ul>
    
        </div>
        <!-- side_navbar -->
      </div>
      <!-- x-show component isOpen -->
    
      <nav class="navbar" role="navigation" aria-label="main navigation">
        <div class="navbar-brand">
          <!-- navbar items, navbar burger... -->
          <a class="navbar-item" href="#">
            <img src="https://picsum.photos/100/100?Grouplogo.svg">
          </a>
    
          <a role="button" class="site-menu " width="32px" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample" @click=" isOpen = !isOpen">
            <img src="https://picsum.photos/32/32?burger_icon.svg">
          </a>
    
        </div>
        <!-- navbar-brand -->
    
        <div id="navbarBasicExample" class="navbar-menu">
    
          <div class="navbar-menu">
            <!-- navbar start, navbar end -->
            <div class="navbar-end">
    
              <div class="navbar-item has-text-weight-medium ">
                <a class="navbar-item">link</a>
                <a class="navbar-item">link</a>
    
              </div>
              <!-- navbar-end -->
    
            </div>
            <!-- x-show component isOpen -->