Tutorial
Create a Bootstrap Like Modal with Tailwind and Alpine.js
This post was updated 01 May - 2020
In certain scenarios, it doesnt really make sense to use LiveView. That can be toggling dropdowns, tabs, accordions and opening modals. There is a great minimal library for that called Alpine.js.
So in this mini-tutorial I will build a bootstrap 4-like animated modal using Tailwind markup and sprinkle some Alpine.js on it.
STEP 1 - Installation
Since I want to use the css transitions that comes with Tailwind 1.2.0 I need to make sure I am on the latest version. And since that is not released yet, I can pull in the latest canary version. So I need to update my package.json
"tailwindcss": "^1.2.0-canary.5"
and install that version run
yarn
To install Alpine.js I will use yarn as well.
yarn add alpinejs
And in my app.js
add
import 'alpinejs'
STEP 2 - Implementation
I ended up giving the modal 3 states. CLOSED, TRANSITION, OPEN
The reason is that I couldnt get the animations working unless I added the extra transition step.
For example, regarding the backdrop. The modal has the initial state CLOSED
. When the button is clicked, I run rhe function open()
. That updates the state to TRANSITION
.
However, It has the initial opacity to 0% with opacity-0
. Then I have a setTimeout(() => { this.state = 'OPEN' }, 50)
that after 50ms changes states top OPEN
and by backdrop changes opacity to opacity-25
.
<!-- BACKDROP -->
<div
:class="{ 'opacity-25': isOpen() }"
class="z-40 fixed top-0 left-0 bottom-0 right-0 bg-black opacity-0 transition-opacity duration-200 linear"
></div>
And I solved the animation and fade in on the modal with the same technique.
NOTE: If there is a better way to do this without the extra transition step, please let me know.
FULL CODE EXAMPLE
<div x-data="modal()">
<button x-on:click="open()" type="button" class="inline-block font-normal text-center px-3 py-2 leading-normal text-base rounded cursor-pointer text-white bg-blue-600" data-toggle="modal" data-target="#exampleModalTwo">
Launch modal
</button>
<!-- MODAL CONTAINER WITH BACKDROP -->
<div x-show="isOpening()">
<!-- MODAL -->
<div
:class="{ 'opacity-0': isOpening(), 'opacity-100': isOpen() }"
class="fixed z-50 top-0 left-0 w-full h-full outline-none transition-opacity duration-200 linear"
tabindex="-1"
role="dialog"
>
<!-- MODAL DIALOG -->
<div
:class="{ 'mt-4': isOpening(), 'mt-8': isOpen() }"
class="relative w-auto pointer-events-none max-w-lg mt-8 mx-auto transition-all duration-200 ease-out"
>
<!-- MODAL CONTAINER -->
<div class="relative flex flex-col w-full pointer-events-auto bg-white border border-gray-300 rounded-lg shadow-xl">
<div class="flex items-start justify-between p-4 border-b border-gray-300 rounded-t">
<h5 class="mb-0 text-lg leading-normal">Awesome Modal</h5>
<button
type="button"
class="close"
x-on:click="close()"
>×</button>
</div>
<div class="relative flex p-4">
...
</div>
<div class="flex items-center justify-end p-4 border-t border-gray-300">
<button
x-on:click="close()"
type="button"
class="inline-block font-normal text-center px-3 py-2 leading-normal text-base rounded cursor-pointer text-white bg-gray-600 mr-2"
>Close</button>
<button
type="button"
class="inline-block font-normal text-center px-3 py-2 leading-normal text-base rounded cursor-pointer text-white bg-blue-600"
>Save changes</button>
</div>
</div>
</div>
</div>
<!-- BACKDROP -->
<div
:class="{ 'opacity-25': isOpen() }"
class="z-40 fixed top-0 left-0 bottom-0 right-0 bg-black opacity-0 transition-opacity duration-200 linear"
></div>
</div>
</div>
<script>
function modal() {
return {
state: 'CLOSED', // [CLOSED, TRANSITION, OPEN]
open() {
this.state = 'TRANSITION'
setTimeout(() => { this.state = 'OPEN' }, 50)
},
close() {
this.state = 'TRANSITION'
setTimeout(() => { this.state = 'CLOSED' }, 300)
},
isOpen() { return this.state === 'OPEN' },
isOpening() { return this.state !== 'CLOSED' },
}
}
</script>
Tag Cloud
Phoenix Bolerplate
Generate a Phoenix Boilerplate and save hours on your next project.
SAAS Starter Kit
Get started and save time and resources by using the SAAS Starter Kit built with Phoenix and LiveView.
Subscribe for $39/mo to geat ahead!
Learn MoreRelated Tutorials
Published 11 Jul - 2020 - Updated 22 May - 2021
Create a reusable modal with LiveView Component
To reduce duplicity and complexity in your apps, Phoenix LiveView comes with the possibility to use reusable components. Each component can have its..