Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 8, 2020 09:55 pm GMT

Tailwind Enter/Leave Transition Effects with Stimulus.js

As a fan of TailwindUI, I was disappointed to find it impossible to support the suggested enter/leave without using Apline.js or Vue.js. The tailwind team even built their own transition component for react support. Working with Ruby on Rails and Stimulus.js I wanted to keep the project close to "core" rails. I didn't feel including Alpine.js or switching to Vue.js just for transitions was optimal. For what it's worth I think both Alpine and Vue are awesome!

Initially, I didn't bother trying. A little bit of research and a few youtube videos later I came up short. I settled on simply hiding/showing the element or applying a generic animation from something such as animate.css. But I just couldn't accept that it was impossible to implement. Plus it didn't look as nice. I dug a little deeper and came across this amazing article. I highly recommend reading it to understand how the transitions are implemented. I learned a lot and give the author a lot of credit!

I was able to take the lessons from the article and abstract it into a handy little npm package el-transition. As I write this el-transition is hot off the press. Please review and contribute!

GitHub logo mmccall10 / el-transition

Apply Enter/Leave transitions


We will use this package to implement our TailwindUI transition effects!

For this example let's build a dropdown component. You can find the tailwind markup here here.

Before we get started install the el-transition package.

$ yarn add el-transition

Time to Code

The following is a direct copy of the dropdown component from TailwindUI's library. Notice the comment specifying the suggested enter/leave transition classes.

<div class="relative inline-block text-left">  <div>    <span class="rounded-md shadow-sm">      <button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150" id="options-menu" aria-haspopup="true" aria-expanded="true">        Options        <svg class="-mr-1 ml-2 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">          <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />        </svg>      </button>    </span>  </div>  <!--    Dropdown panel, show/hide based on dropdown state.    Entering: "transition ease-out duration-100"      From: "transform opacity-0 scale-95"      To: "transform opacity-100 scale-100"    Leaving: "transition ease-in duration-75"      From: "transform opacity-100 scale-100"      To: "transform opacity-0 scale-95"  -->  <div class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">    <div class="rounded-md bg-white shadow-xs">      <div class="py-1" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">Account settings</a>        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">Support</a>        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">License</a>        <form method="POST" action="#">          <button type="submit" class="block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">            Sign out          </button>        </form>      </div>    </div>  </div></div>

Now let's create a dropdown stimulus controller we can connect to our dropdown element. We will add two targets button and menu and the toggleMenu function.

// dropdown_controller.jsimport {Controller} from "stimulus"export default class extends Controller {    static targets = ["menu", "button"]    toggleMenu() {        if (this.menuTarget.classList.contains('hidden')) {            // enter transition        } else {            // leave transition        }    }}

Now we can connect the controller to the dropdown.

<!-- add dropdown controller --><div data-controller="dropdown" class="relative inline-block text-left">  <div>    <span class="rounded-md shadow-sm">      <!-- Add button target and click action -->      <button type="button" data-target="dropdown.button" data-action="click->dropdown#toggleMenu" class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150" id="options-menu" aria-haspopup="true" aria-expanded="true">        Options        <svg class="-mr-1 ml-2 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">          <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />        </svg>      </button>    </span>  </div>  <!-- add menu target -->  <div data-target="dropdown.menu" class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">    <div class="rounded-md bg-white shadow-xs">      <div class="py-1" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">Account settings</a>        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">Support</a>        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">License</a>        <form method="POST" action="#">          <button type="submit" class="block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">            Sign out          </button>        </form>      </div>    </div>  </div></div>

Now that the controller is connected let's implement the suggested transitions.

 <!--    Dropdown panel, show/hide based on dropdown state.    Entering: "transition ease-out duration-100"      From: "transform opacity-0 scale-95"      To: "transform opacity-100 scale-100"    Leaving: "transition ease-in duration-75"      From: "transform opacity-100 scale-100"      To: "transform opacity-0 scale-95"  -->

To do this, el-transiton expects data-transition-* attributes or an animation class. We will use data attributes which is more in line with how Apline.js works. Here is our updated html with the transitions declared.

<div data-controller="dropdown" class="relative inline-block text-left">  <div>    <span class="rounded-md shadow-sm">      <button type="button" data-target="dropdown.button" data-action="click->dropdown#toggleMenu" class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150" id="options-menu" aria-haspopup="true" aria-expanded="true">        Options        <svg class="-mr-1 ml-2 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">          <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />        </svg>      </button>    </span>  </div><!-- add transition data attributes. --><div class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg hidden"       data-target="dropdown.menu"       data-transition-enter="transition ease-out duration-100"       data-transition-enter-start="transform opacity-0 scale-95"       data-transition-enter-end="transform opacity-100 scale-100"       data-transition-leave="transition ease-in duration-75"       data-transition-leave-start="transform opacity-100 scale-100"       data-transition-leave-end="transform opacity-0 scale-95"  >    <div class="rounded-md bg-white shadow-xs">      <div class="py-1" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">Account settings</a>        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">Support</a>        <a href="#" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">License</a>        <form method="POST" action="#">          <button type="submit" class="block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" role="menuitem">            Sign out          </button>        </form>      </div>    </div>  </div></div>

Finally, we can update our stimulus dropdown controller to execute the enter/leave transition effects.

import {Controller} from "stimulus"// import the enter leave functionsimport {enter, leave} from 'el-transition'; export default class extends Controller {    static targets = ["menu", "button"]    // call the enter and leave functions    toggleMenu() {        if(this.menuTarget.classList.contains('hidden')) {            enter(this.menuTarget)        } else {            leave(this.menuTarget)        }    }}

That's it!

You can find a demo here:

Conclusion

I am stoked to be able to support TailwindUI's suggested transition effects as the team puts a lot of care into it and they look nice! While this example is specific to stimulus.js the el-transition is framework agnostic.


Original Link: https://dev.to/mmccall10/tailwind-enter-leave-transition-effects-with-stimulus-js-5hl7

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To