This is a repository that shows how to create a global modal which is equivalent to browser window.confirm
with Alpinejs.
You can call window.customConfirm
to get boolean true
or false
like below.
isConfirmed = await window.customConfirm({...});
console.log(isConfirmed) // π true or false
Please create Static HTML project at https://stackblitz.com/
We, only use two files
index.html
script.js
In index.html
, add Alpine.js cdn
<html>
<head>
<meta charset="UTF-8" />
<!-- Custom script -->
<script src="script.js"></script>
<!-- π Alpine.js from cdn -->
<script
defer
src="https://unpkg.com/[email protected]/dist/cdn.min.js"
></script>
</head>
<body>
...
</body>
</html>
In script.js
window.customConfirm = () => {
console.log('customConfirm called');
};
In index.html
<button
x-data
@click="
window.customConfirm();
"
>
open dialog
</button>
Now, we defined window.customConfirm
function and can call it from button by using Alpinejs.
In this step, we're going to add modal.
Please modify index.html
like below.
index.html
<body>
<!-- Mimic nested div -->
<div>
<div>
<button x-data @click="window.customConfirm();">open dialog</button>
</div>
</div>
<!-- Modal -->
<div style="background: pink; border: solid; padding: 40px">
<h1>Modal Title</h1>
<p>Modal message</p>
<button>Cancel</button>
<button>OK</button>
</div>
</body>
To handle modal's open
state, let's add Alpine store.
script.js
document.addEventListener('alpine:init', () => {
Alpine.store('confirmModal', {
open: false,
toggle() {
this.open = !this.open;
},
});
});
Then in index.html
<body>
...
<!-- Modal -->
<div x-data x-show="$store.confirmModal.open"> <!-- π Add this line -->
<div style="background: pink; border: solid; padding: 40px">
<h1>Modal Title</h1>
<p>Modal message</p>
<button>Cancel</button>
<button>OK</button>
</div>
</div>
</body>
And then,
script.js
window.customConfirm = () => {
Alpine.store('confirmModal').toggle();
};
Now we can toggle modal like below.
In this step, we're going to add function when modal OK and Cancel is clicked.
script.js
π« Note: this code is for showing wrong implementation.
document.addEventListener('alpine:init', () => {
Alpine.store('confirmModal', {
open: false,
toggle() {
this.open = !this.open;
},
onOk() {
console.log('onOk clicked');
return true;
},
onCancel() {
console.log('onCancel clicked');
return false;
},
});
});
Then in index.html
...
<!-- Mimic nested div -->
<div>
<div>
<button
x-data
@click="
isConfirmed = window.customConfirm();
console.log(isConfirmed);
"
>
open dialog
</button>
</div>
</div>
<!-- Modal -->
<div x-data x-show="$store.confirmModal.open">
<div style="background: pink; border: solid; padding: 40px">
<h1>Modal Title</h1>
<p>Modal message</p>
<button
@click="
$store.confirmModal.onCancel();
"
>
Cancel
</button>
<button
@click="
$store.confirmModal.onOk();
"
>
OK
</button>
</div>
</div>
...
Now, we can assign onOk
and onCancel
function to buttons in modal.
π« But, it does not return boolean true
or false
value.
In the next step, we will learn how to fix this issue.
To get boolean value from window.customConfirm
, we need to use Promise
.
For example, let's re write window.customConfirm
script.js
window.customConfirm = () => {
return new Promise((resolve, reject) => {
resolve(true);
// resolve(123) π try returning various values by using `resolve`
// resolve("hoge")
});
// Alpine.store('confirmModal').toggle();
};
And in index.html
<button
x-data
@click="
isConfirmed = await window.customConfirm();
console.log(isConfirmed);
"
>
open dialog
</button>
Alpine @click
does not need to declare async
, just using await
is enough.
You will see now, window.customConfirm
returns boolean true
value in console.
First we make store onOk
and onCancel
blank function at begining.
document.addEventListener('alpine:init', () => {
Alpine.store('confirmModal', {
open: false,
toggle() {
this.open = !this.open;
},
onOk() {},
onCancel() {},
});
});
Then modify window.customConfirm
like below.
window.customConfirm = () => {
return new Promise((resolve, reject) => {
const confirmModal = Alpine.store('confirmModal');
// Open Modal
confirmModal.open = true;
// Assign logic: when OK button is clicked, close modal and return true
confirmModal.onOk = () => {
confirmModal.open = false;
resolve(true);
};
// Assign logic: when Cancel button is clicked, close modal and return false
confirmModal.onCancel = () => {
confirmModal.open = false;
resolve(false);
};
});
};
By doing this, we override onOk
and onCancel
logic when window.customConfirm
is called to return boolean true
or false
.
This is the final code of this tutorial.
https://web-platform-rrgo1m.stackblitz.io
And this is a confirm modal with tailwind which is shown in Intro section. https://stackblitz.com/edit/web-platform-nwc4sm
π This example is totaly inspired by this great stackoverflow answer https://stackoverflow.com/a/58891905/6037441