Skip to content

Instantly share code, notes, and snippets.

@Rod911
Created January 4, 2023 10:35
Show Gist options
  • Save Rod911/2adaeda45f3072706223bf7d3bcb2599 to your computer and use it in GitHub Desktop.
Save Rod911/2adaeda45f3072706223bf7d3bcb2599 to your computer and use it in GitHub Desktop.
Create Popup
<button class="popup-btn1">Popup</button>
<div class="popup-wrapper" id="popup1">
<div class="popup-overlay popup-dismiss"></div>
<div class="popup-container">
<button class="popup-close popup-dismiss">&times;</button>
<div class="popup-content"> </div>
</div>
</div>
<button class="popup-btn2">Popup sidemenu</button>
<div class="popup-wrapper popup-slide-in" id="popup2">
<div class="popup-overlay popup-dismiss"></div>
<div class="popup-container" style="max-width: 350px;">
<button class="popup-close popup-dismiss">&times;</button>
<h3 class="popup-title">Popup</h3>
<div class="popup-content"> </div>
</div>
</div>
<button class="popup-btn3">Popup new</button>
<script>
document.addEventListener("DOMContentLoaded", function() {
var popup1 = setUpPopup(document.querySelector("#popup1"), ".popup-btn1");
var popup2 = setUpPopup(document.querySelector("#popup2"), ".popup-btn2");
let newPopup = createPopup({
id: "test",
trigger: ".popup-btn3",
slideIn: true,
});
});
</script>
/**
* @param {HTMLElement} popup Popup container
* @param {String} trigger Open popup trigger selector
* @param {Number} autoOpen Auto Open delay
* @returns {{
* popup: HTMLElement,
* openPopup: Function,
* dismissPopup: Function,
* on: {
* open: Function,
* close: Function
* }
* }}
*/
function setUpPopup(popup, trigger = "", autoOpen = false) {
if (!popup) return;
if (autoOpen)
setTimeout(() => {
openPopup();
}, parseInt(autoOpen));
let on = {
open: function (obj = null) {},
close: function (obj = null) {}
};
popup.querySelectorAll(".popup-dismiss").forEach((dismiss) => {
dismiss.addEventListener("click", dismissPopup);
});
if (trigger) {
document.querySelectorAll(trigger).forEach((triggerElement) => {
triggerElement.addEventListener("click", openPopup);
});
}
/**
* @param {MouseEvent} e
*/
function dismissPopup(e = null) {
popup.classList.add("popup-closing");
setTimeout(() => {
popup.classList.remove("popup-active", "popup-closing");
}, 500);
document.documentElement.classList.remove("popup-open");
on.close();
window.activePopup = null;
}
/**
* @param {MouseEvent} e
*/
function openPopup(e = null) {
if (e) e.preventDefault();
let scrollbarWidth = window.innerWidth - document.body.clientWidth + "px";
document.documentElement.setAttribute(
"style",
"--scrollbar-width: " + scrollbarWidth
);
if (window.activePopup && window.activePopup.dismissPopup) {
window.activePopup.dismissPopup();
}
popup.classList.add("popup-active");
document.documentElement.classList.add("popup-open");
on.open(e);
window.activePopup = popup;
}
var popupWrapper = {
popup,
openPopup,
dismissPopup,
on
};
popup.openPopup = openPopup;
popup.dismissPopup = dismissPopup;
return popupWrapper;
}
/**
* Create HTMLElement from HTML string
* @param {String} htmlString
* @returns {HTMLElement}
*/
function createElementFromHTML(htmlString) {
var div = document.createElement("div");
div.innerHTML = htmlString.trim();
return div.firstChild;
}
/**
* @param {{
* id: String,
* trigger: String|null,
* autoOpen: number|null,
* slideIn: Boolean,
* slideFromLeft: Boolean|null,
* title: String|null,
* popupHTML: String | HTMLElement | null
* }} options
*/
function createPopup(options) {
if (options.popupHTML instanceof Element) {
options.popupHTML = options.popupHTML.outerHTML;
}
let popupTemplate = `<div class="popup-wrapper ${
options.slideIn ? "popup-slide-in" : ""
}" data-slide-dir="${
options.slideIn && options.slideFromLeft ? "left" : "right"
}" id="${
options.id
}"><div class="popup-overlay popup-dismiss"></div><div class="popup-container"><button class="popup-close popup-dismiss">&times;</button>${
options.title ? `<h3 class="popup-title">${options.title}</h3>` : ``
}<div class="popup-content">${
options.popupHTML ? options.popupHTML : ""
}</div></div></div>`;
let popupElement = createElementFromHTML(popupTemplate);
document.body.appendChild(popupElement);
let popup = setUpPopup(popupElement, options.trigger, options.autoOpen);
return popup;
}
:root {
--scrollbar-width: 1rem;
}
html.popup-open {
overflow: hidden;
padding-right: var(--scrollbar-width);
}
.popup-wrapper {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
/* display: none; */
visibility: hidden;
z-index: 50;
opacity: 0;
transition: ease-in-out 0.25s opacity;
}
.popup-wrapper.popup-closing,
.popup-wrapper.popup-active {
/* display: block; */
visibility: visible;
opacity: 1;
}
.popup-wrapper .popup-overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: #000;
opacity: 0.6;
transition: ease 0.3s opacity;
transition-delay: 0.3s;
}
.popup-wrapper.popup-active .popup-overlay {
opacity: 0.8;
transition-delay: 0s;
}
.popup-container {
position: absolute;
top: 50%;
left: 50%;
width: 550px;
height: 400px;
max-width: calc(100% - 20px);
max-height: calc(100% - 40px);
transform: translate(-50%, -20%);
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.15);
transition: ease 0.25s transform 0.2s, ease 0.3s opacity 0s;
opacity: 0;
}
.popup-slide-in .popup-container {
top: 0;
right: 0;
height: 100%;
max-height: none;
border-radius: 0;
left: auto;
transform: translate(100%, 0);
padding-top: 15px;
display: grid;
grid-template-rows: 2rem 1fr;
}
.popup-slide-in[data-slide-dir="left"] .popup-container {
left: 0;
right: auto;
transform: translateX(-100%);
}
.popup-wrapper.popup-active .popup-container {
transform: translate(-50%, -50%);
transition-delay: 0s, 0s;
opacity: 1;
}
.popup-slide-in.popup-active .popup-container {
transform: translate(0, 0);
}
.popup-wrapper.popup-closing .popup-overlay {
opacity: 0;
transition: ease 0.3s opacity;
}
.popup-wrapper.popup-closing .popup-container {
opacity: 0;
transform: translate(-50%, -30%);
transition: ease 0.25s transform 0s, ease 0.3s opacity 0s;
}
.popup-slide-in.popup-closing .popup-container {
transform: translate(100%, 0);
}
.popup-slide-in.popup-closing[data-slide-dir="left"] .popup-container {
transform: translateX(-100%);
}
.popup-container .popup-close {
position: absolute;
top: 20px;
right: 20px;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
width: 25px;
height: 25px;
background-color: #fff;
/* border: 1px solid #aaa; */
border: none;
color: #999;
font-size: 26px;
font-weight: 600;
border-radius: 50px;
transform: translate(45%, -45%);
cursor: pointer;
}
.popup-content {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-evenly;
overflow: auto;
padding: 20px 0;
}
.popup-slide-in .popup-content {
align-items: stretch;
justify-content: flex-start;
padding-bottom: 10px;
}
.popup-title {
font-weight: 600;
font-size: 18px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment