An Interest In:
Web News this Week
- April 27, 2024
- April 26, 2024
- April 25, 2024
- April 24, 2024
- April 23, 2024
- April 22, 2024
- April 21, 2024
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!
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
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To