I’ll build this as a strong standalone popup chunk for RX Theme: reusable popup manager, triggers, accessibility, cookies/localStorage, exit intent, scroll/time triggers, newsletter/content modal support, and safe WordPress-friendly initialization.
Below is an advanced chunk-026-popup.js file for:
assets/static-js/static-chunks-js/chunk-026-popup.js
It is safe for RX Theme, plain JavaScript, no jQuery, WordPress-friendly, accessibility-focused, and supports many popup systems: time popup, scroll popup, exit intent, click trigger, cookie/localStorage limit, focus trap, ESC close, overlay close, mobile-safe behavior, analytics hooks, and custom events.
/*!
* RX Theme Popup Chunk
* File: assets/static-js/static-chunks-js/chunk-026-popup.js
* Purpose: Advanced popup/modal system for RX Theme
* Author: RX Theme
* Version: 1.0.0
*/
(function () {
"use strict";
/**
* RX Popup Manager
*
* Supported features:
* - Time delayed popup
* - Scroll depth popup
* - Exit intent popup
* - Click trigger popup
* - Auto open popup
* - Cookie/localStorage frequency control
* - Accessibility support
* - Focus trap
* - ESC key close
* - Overlay click close
* - Body scroll lock
* - Newsletter popup
* - Content popup
* - Confirm popup
* - Custom events
* - WordPress-friendly hooks
*/
var RXPopup = {
version: "1.0.0",
defaults: {
selector: "[data-rx-popup]",
triggerSelector: "[data-rx-popup-trigger]",
closeSelector: "[data-rx-popup-close]",
overlayClass: "rx-popup-overlay",
activeClass: "is-active",
visibleClass: "is-visible",
bodyOpenClass: "rx-popup-open",
animationInClass: "rx-popup-animate-in",
animationOutClass: "rx-popup-animate-out",
storagePrefix: "rx_popup_",
storageType: "localStorage", // localStorage, sessionStorage, cookie
cookieDays: 7,
focusableSelectors:
'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable="true"]',
closeOnOverlay: true,
closeOnEsc: true,
lockBodyScroll: true,
restoreFocus: true,
debug: false
},
state: {
initialized: false,
activePopup: null,
lastFocusedElement: null,
scrollTriggersFired: {},
timeTriggersFired: {},
exitIntentFired: false,
resizeTimer: null,
scrollTimer: null
},
/**
* Init popup system
*/
init: function (options) {
if (this.state.initialized) {
return;
}
this.settings = this.extend({}, this.defaults, options || {});
this.cacheElements();
this.bindEvents();
this.preparePopups();
this.initAutoTriggers();
this.state.initialized = true;
this.dispatch("rxPopupReady", {
version: this.version
});
this.log("RX Popup initialized");
},
/**
* Cache DOM elements
*/
cacheElements: function () {
this.popups = Array.prototype.slice.call(
document.querySelectorAll(this.settings.selector)
);
this.triggers = Array.prototype.slice.call(
document.querySelectorAll(this.settings.triggerSelector)
);
this.closeButtons = Array.prototype.slice.call(
document.querySelectorAll(this.settings.closeSelector)
);
},
/**
* Prepare all popup elements
*/
preparePopups: function () {
var self = this;
this.popups.forEach(function (popup, index) {
var id = popup.getAttribute("id");
if (!id) {
id = "rx-popup-" + (index + 1);
popup.setAttribute("id", id);
}
popup.setAttribute("role", popup.getAttribute("role") || "dialog");
popup.setAttribute("aria-modal", "true");
popup.setAttribute("aria-hidden", "true");
if (!popup.hasAttribute("tabindex")) {
popup.setAttribute("tabindex", "-1");
}
var labelledBy = popup.getAttribute("data-rx-popup-labelledby");
if (labelledBy) {
popup.setAttribute("aria-labelledby", labelledBy);
}
var describedBy = popup.getAttribute("data-rx-popup-describedby");
if (describedBy) {
popup.setAttribute("aria-describedby", describedBy);
}
self.createOverlayIfNeeded(popup);
});
},
/**
* Create overlay if popup needs it
*/
createOverlayIfNeeded: function (popup) {
var hasOverlay = popup.getAttribute("data-rx-popup-overlay");
if (hasOverlay === "false") {
return;
}
var popupId = popup.getAttribute("id");
var existingOverlay = document.querySelector(
'[data-rx-popup-overlay-for="' + popupId + '"]'
);
if (existingOverlay) {
return;
}
var overlay = document.createElement("div");
overlay.className = this.settings.overlayClass;
overlay.setAttribute("data-rx-popup-overlay-for", popupId);
overlay.setAttribute("aria-hidden", "true");
popup.parentNode.insertBefore(overlay, popup);
},
/**
* Bind global and element events
*/
bindEvents: function () {
var self = this;
document.addEventListener("click", function (event) {
self.handleDocumentClick(event);
});
document.addEventListener("keydown", function (event) {
self.handleKeydown(event);
});
window.addEventListener(
"scroll",
function () {
self.throttleScroll();
},
{ passive: true }
);
window.addEventListener("resize", function () {
clearTimeout(self.state.resizeTimer);
self.state.resizeTimer = setTimeout(function () {
self.handleResize();
}, 150);
});
document.addEventListener("mouseleave", function (event) {
self.handleExitIntent(event);
});
document.addEventListener("visibilitychange", function () {
self.handleVisibilityChange();
});
},
/**
* Handle all document click events
*/
handleDocumentClick: function (event) {
var trigger = event.target.closest(this.settings.triggerSelector);
var closeBtn = event.target.closest(this.settings.closeSelector);
var overlay = event.target.closest("." + this.settings.overlayClass);
if (trigger) {
event.preventDefault();
var targetId = trigger.getAttribute("data-rx-popup-trigger");
var popup = this.getPopupById(targetId);
if (popup) {
this.open(popup, {
source: "click",
trigger: trigger
});
}
return;
}
if (closeBtn) {
event.preventDefault();
var popupToClose = closeBtn.closest(this.settings.selector);
if (popupToClose) {
this.close(popupToClose, {
source: "close-button"
});
} else {
this.closeActive({
source: "close-button"
});
}
return;
}
if (
overlay &&
this.settings.closeOnOverlay &&
this.state.activePopup
) {
var overlayFor = overlay.getAttribute("data-rx-popup-overlay-for");
if (
overlayFor &&
this.state.activePopup.getAttribute("id") === overlayFor
) {
this.close(this.state.activePopup, {
source: "overlay"
});
}
}
},
/**
* Handle keyboard controls
*/
handleKeydown: function (event) {
if (!this.state.activePopup) {
return;
}
if (event.key === "Escape" && this.settings.closeOnEsc) {
event.preventDefault();
this.close(this.state.activePopup, {
source: "escape"
});
return;
}
if (event.key === "Tab") {
this.trapFocus(event, this.state.activePopup);
}
},
/**
* Open popup
*/
open: function (popup, meta) {
if (!popup) {
return;
}
if (typeof popup === "string") {
popup = this.getPopupById(popup);
}
if (!popup) {
return;
}
var popupId = popup.getAttribute("id");
if (!this.canShow(popup)) {
this.log("Popup blocked by frequency control:", popupId);
return;
}
if (this.state.activePopup && this.state.activePopup !== popup) {
this.close(this.state.activePopup, {
source: "switch"
});
}
this.state.lastFocusedElement = document.activeElement;
this.state.activePopup = popup;
popup.classList.remove(this.settings.animationOutClass);
popup.classList.add(
this.settings.activeClass,
this.settings.visibleClass,
this.settings.animationInClass
);
popup.setAttribute("aria-hidden", "false");
var overlay = this.getOverlay(popup);
if (overlay) {
overlay.classList.add(this.settings.activeClass, this.settings.visibleClass);
}
if (this.settings.lockBodyScroll) {
this.lockBodyScroll();
}
this.focusPopup(popup);
this.markShown(popup);
this.dispatch("rxPopupOpen", {
popup: popup,
id: popupId,
meta: meta || {}
});
this.log("Popup opened:", popupId);
},
/**
* Close popup
*/
close: function (popup, meta) {
if (!popup) {
return;
}
if (typeof popup === "string") {
popup = this.getPopupById(popup);
}
if (!popup) {
return;
}
var self = this;
var popupId = popup.getAttribute("id");
var animationDuration = this.getAnimationDuration(popup);
popup.classList.remove(this.settings.animationInClass);
popup.classList.add(this.settings.animationOutClass);
popup.setAttribute("aria-hidden", "true");
var overlay = this.getOverlay(popup);
if (overlay) {
overlay.classList.remove(this.settings.visibleClass);
}
setTimeout(function () {
popup.classList.remove(
self.settings.activeClass,
self.settings.visibleClass,
self.settings.animationOutClass
);
if (overlay) {
overlay.classList.remove(self.settings.activeClass);
}
if (self.state.activePopup === popup) {
self.state.activePopup = null;
}
if (!self.state.activePopup && self.settings.lockBodyScroll) {
self.unlockBodyScroll();
}
if (self.settings.restoreFocus && self.state.lastFocusedElement) {
try {
self.state.lastFocusedElement.focus();
} catch (error) {
self.log("Focus restore failed", error);
}
}
self.dispatch("rxPopupClose", {
popup: popup,
id: popupId,
meta: meta || {}
});
self.log("Popup closed:", popupId);
}, animationDuration);
},
/**
* Close active popup
*/
closeActive: function (meta) {
if (this.state.activePopup) {
this.close(this.state.activePopup, meta || {});
}
},
/**
* Toggle popup
*/
toggle: function (popup, meta) {
if (typeof popup === "string") {
popup = this.getPopupById(popup);
}
if (!popup) {
return;
}
if (popup.classList.contains(this.settings.activeClass)) {
this.close(popup, meta || {});
} else {
this.open(popup, meta || {});
}
},
/**
* Auto trigger systems
*/
initAutoTriggers: function () {
var self = this;
this.popups.forEach(function (popup) {
self.initTimeTrigger(popup);
self.initAutoOpenTrigger(popup);
});
},
/**
* Time delay popup
*
* HTML:
* <div data-rx-popup data-rx-popup-delay="3000"></div>
*/
initTimeTrigger: function (popup) {
var delay = parseInt(popup.getAttribute("data-rx-popup-delay"), 10);
if (!delay || delay < 1) {
return;
}
var popupId = popup.getAttribute("id");
if (this.state.timeTriggersFired[popupId]) {
return;
}
var self = this;
setTimeout(function () {
if (!self.state.timeTriggersFired[popupId]) {
self.state.timeTriggersFired[popupId] = true;
self.open(popup, {
source: "time",
delay: delay
});
}
}, delay);
},
/**
* Auto open popup
*
* HTML:
* <div data-rx-popup data-rx-popup-auto="true"></div>
*/
initAutoOpenTrigger: function (popup) {
var auto = popup.getAttribute("data-rx-popup-auto");
if (auto !== "true") {
return;
}
var self = this;
requestAnimationFrame(function () {
self.open(popup, {
source: "auto"
});
});
},
/**
* Scroll trigger throttling
*/
throttleScroll: function () {
var self = this;
if (this.state.scrollTimer) {
return;
}
this.state.scrollTimer = setTimeout(function () {
self.state.scrollTimer = null;
self.handleScrollTriggers();
}, 120);
},
/**
* Scroll depth popup
*
* HTML:
* <div data-rx-popup data-rx-popup-scroll="60"></div>
*/
handleScrollTriggers: function () {
var self = this;
var scrollPercent = this.getScrollPercent();
this.popups.forEach(function (popup) {
var targetPercent = parseInt(
popup.getAttribute("data-rx-popup-scroll"),
10
);
if (!targetPercent || targetPercent < 1) {
return;
}
var popupId = popup.getAttribute("id");
if (self.state.scrollTriggersFired[popupId]) {
return;
}
if (scrollPercent >= targetPercent) {
self.state.scrollTriggersFired[popupId] = true;
self.open(popup, {
source: "scroll",
scrollPercent: scrollPercent,
targetPercent: targetPercent
});
}
});
},
/**
* Exit intent popup
*
* HTML:
* <div data-rx-popup data-rx-popup-exit="true"></div>
*/
handleExitIntent: function (event) {
if (this.state.exitIntentFired) {
return;
}
if (event.clientY > 10) {
return;
}
var popup = this.popups.find(function (item) {
return item.getAttribute("data-rx-popup-exit") === "true";
});
if (!popup) {
return;
}
this.state.exitIntentFired = true;
this.open(popup, {
source: "exit-intent"
});
},
/**
* Browser tab visibility event
*/
handleVisibilityChange: function () {
if (document.hidden) {
this.dispatch("rxPopupPageHidden", {});
} else {
this.dispatch("rxPopupPageVisible", {});
}
},
/**
* Resize handler
*/
handleResize: function () {
if (this.state.activePopup) {
this.dispatch("rxPopupResize", {
popup: this.state.activePopup
});
}
},
/**
* Frequency control
*/
canShow: function (popup) {
var id = popup.getAttribute("id");
var once = popup.getAttribute("data-rx-popup-once");
var frequency = popup.getAttribute("data-rx-popup-frequency");
var storageKey = this.settings.storagePrefix + id;
var stored = this.getStorage(storageKey);
if (once === "true" && stored) {
return false;
}
if (frequency) {
var hours = parseFloat(frequency);
if (!isNaN(hours) && stored) {
var lastShown = parseInt(stored, 10);
var now = Date.now();
var limit = hours * 60 * 60 * 1000;
if (now - lastShown < limit) {
return false;
}
}
}
return true;
},
/**
* Mark popup as shown
*/
markShown: function (popup) {
var id = popup.getAttribute("id");
var once = popup.getAttribute("data-rx-popup-once");
var frequency = popup.getAttribute("data-rx-popup-frequency");
if (once === "true" || frequency) {
this.setStorage(this.settings.storagePrefix + id, String(Date.now()));
}
},
/**
* Storage get
*/
getStorage: function (key) {
try {
if (this.settings.storageType === "sessionStorage") {
return window.sessionStorage.getItem(key);
}
if (this.settings.storageType === "cookie") {
return this.getCookie(key);
}
return window.localStorage.getItem(key);
} catch (error) {
this.log("Storage get failed:", error);
return null;
}
},
/**
* Storage set
*/
setStorage: function (key, value) {
try {
if (this.settings.storageType === "sessionStorage") {
window.sessionStorage.setItem(key, value);
return;
}
if (this.settings.storageType === "cookie") {
this.setCookie(key, value, this.settings.cookieDays);
return;
}
window.localStorage.setItem(key, value);
} catch (error) {
this.log("Storage set failed:", error);
}
},
/**
* Cookie set
*/
setCookie: function (name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
expires = "; expires=" + date.toUTCString();
}
document.cookie =
encodeURIComponent(name) +
"=" +
encodeURIComponent(value || "") +
expires +
"; path=/; SameSite=Lax";
},
/**
* Cookie get
*/
getCookie: function (name) {
var nameEQ = encodeURIComponent(name) + "=";
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i];
while (cookie.charAt(0) === " ") {
cookie = cookie.substring(1, cookie.length);
}
if (cookie.indexOf(nameEQ) === 0) {
return decodeURIComponent(cookie.substring(nameEQ.length));
}
}
return null;
},
/**
* Focus popup
*/
focusPopup: function (popup) {
var autofocus = popup.querySelector("[autofocus]");
var focusable = this.getFocusableElements(popup);
if (autofocus) {
autofocus.focus();
return;
}
if (focusable.length) {
focusable[0].focus();
return;
}
popup.focus();
},
/**
* Get focusable elements
*/
getFocusableElements: function (container) {
return Array.prototype.slice
.call(container.querySelectorAll(this.settings.focusableSelectors))
.filter(function (element) {
return (
element.offsetWidth > 0 ||
element.offsetHeight > 0 ||
element === document.activeElement
);
});
},
/**
* Trap focus inside popup
*/
trapFocus: function (event, popup) {
var focusable = this.getFocusableElements(popup);
if (!focusable.length) {
event.preventDefault();
popup.focus();
return;
}
var first = focusable[0];
var last = focusable[focusable.length - 1];
if (event.shiftKey && document.activeElement === first) {
event.preventDefault();
last.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault();
first.focus();
}
},
/**
* Body scroll lock
*/
lockBodyScroll: function () {
var scrollY = window.scrollY || window.pageYOffset;
document.body.dataset.rxPopupScrollY = String(scrollY);
document.body.style.position = "fixed";
document.body.style.top = "-" + scrollY + "px";
document.body.style.left = "0";
document.body.style.right = "0";
document.body.style.width = "100%";
document.body.classList.add(this.settings.bodyOpenClass);
},
/**
* Body scroll unlock
*/
unlockBodyScroll: function () {
var scrollY = document.body.dataset.rxPopupScrollY;
document.body.style.position = "";
document.body.style.top = "";
document.body.style.left = "";
document.body.style.right = "";
document.body.style.width = "";
document.body.classList.remove(this.settings.bodyOpenClass);
if (scrollY) {
window.scrollTo(0, parseInt(scrollY, 10));
}
delete document.body.dataset.rxPopupScrollY;
},
/**
* Get popup by ID
*/
getPopupById: function (id) {
if (!id) {
return null;
}
id = id.replace("#", "");
return document.getElementById(id);
},
/**
* Get overlay for popup
*/
getOverlay: function (popup) {
var id = popup.getAttribute("id");
if (!id) {
return null;
}
return document.querySelector(
'[data-rx-popup-overlay-for="' + id + '"]'
);
},
/**
* Get page scroll percentage
*/
getScrollPercent: function () {
var scrollTop = window.scrollY || window.pageYOffset;
var docHeight = document.documentElement.scrollHeight;
var winHeight = window.innerHeight;
var scrollable = docHeight - winHeight;
if (scrollable <= 0) {
return 100;
}
return Math.round((scrollTop / scrollable) * 100);
},
/**
* Get CSS animation duration
*/
getAnimationDuration: function (element) {
var styles = window.getComputedStyle(element);
var duration = styles.animationDuration || styles.transitionDuration;
if (!duration) {
return 250;
}
var durations = duration.split(",").map(function (value) {
value = value.trim();
if (value.indexOf("ms") > -1) {
return parseFloat(value);
}
if (value.indexOf("s") > -1) {
return parseFloat(value) * 1000;
}
return 250;
});
return Math.max.apply(null, durations) || 250;
},
/**
* Public method: open by ID
*/
openById: function (id) {
this.open(id, {
source: "api"
});
},
/**
* Public method: close by ID
*/
closeById: function (id) {
this.close(id, {
source: "api"
});
},
/**
* Public method: destroy popup system
*/
destroy: function () {
this.closeActive({
source: "destroy"
});
this.state.initialized = false;
this.state.activePopup = null;
this.state.lastFocusedElement = null;
this.dispatch("rxPopupDestroy", {});
},
/**
* Dispatch custom event
*/
dispatch: function (name, detail) {
var event;
try {
event = new CustomEvent(name, {
detail: detail || {}
});
} catch (error) {
event = document.createEvent("CustomEvent");
event.initCustomEvent(name, true, true, detail || {});
}
document.dispatchEvent(event);
},
/**
* Extend object helper
*/
extend: function () {
var output = arguments[0] || {};
for (var i = 1; i < arguments.length; i++) {
if (!arguments[i]) {
continue;
}
for (var key in arguments[i]) {
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
output[key] = arguments[i][key];
}
}
}
return output;
},
/**
* Debug logger
*/
log: function () {
if (!this.settings || !this.settings.debug) {
return;
}
if (window.console && typeof window.console.log === "function") {
window.console.log.apply(window.console, arguments);
}
}
};
/**
* RX Popup HTML Builder
*
* Allows dynamic popup creation by JavaScript.
*/
var RXPopupBuilder = {
create: function (options) {
var settings = this.extend(
{
id: "rx-dynamic-popup-" + Date.now(),
title: "",
content: "",
closeText: "Close",
size: "medium",
type: "content",
showClose: true,
extraClass: ""
},
options || {}
);
var popup = document.createElement("div");
popup.className =
"rx-popup rx-popup--" +
settings.size +
" rx-popup--" +
settings.type +
" " +
settings.extraClass;
popup.setAttribute("id", settings.id);
popup.setAttribute("data-rx-popup", "");
popup.setAttribute("role", "dialog");
popup.setAttribute("aria-modal", "true");
popup.setAttribute("aria-hidden", "true");
var html = "";
if (settings.showClose) {
html +=
'<button type="button" class="rx-popup__close" data-rx-popup-close aria-label="' +
this.escape(settings.closeText) +
'">×</button>';
}
html += '<div class="rx-popup__inner">';
if (settings.title) {
html +=
'<h2 class="rx-popup__title">' +
this.escape(settings.title) +
"</h2>";
}
html += '<div class="rx-popup__content">';
html += settings.content;
html += "</div>";
html += "</div>";
popup.innerHTML = html;
document.body.appendChild(popup);
if (window.RXPopup && window.RXPopup.state.initialized) {
window.RXPopup.popups.push(popup);
window.RXPopup.preparePopups();
}
return popup;
},
alert: function (message, title) {
var popup = this.create({
title: title || "Notice",
content:
'<p class="rx-popup__message">' + this.escape(message) + "</p>",
type: "alert",
size: "small"
});
window.RXPopup.open(popup, {
source: "builder-alert"
});
return popup;
},
confirm: function (options) {
var settings = this.extend(
{
title: "Are you sure?",
message: "",
confirmText: "Confirm",
cancelText: "Cancel",
onConfirm: null,
onCancel: null
},
options || {}
);
var content =
'<p class="rx-popup__message">' +
this.escape(settings.message) +
"</p>" +
'<div class="rx-popup__actions">' +
'<button type="button" class="rx-popup__button rx-popup__button--confirm" data-rx-confirm-action="confirm">' +
this.escape(settings.confirmText) +
"</button>" +
'<button type="button" class="rx-popup__button rx-popup__button--cancel" data-rx-confirm-action="cancel">' +
this.escape(settings.cancelText) +
"</button>" +
"</div>";
var popup = this.create({
title: settings.title,
content: content,
type: "confirm",
size: "small"
});
popup.addEventListener("click", function (event) {
var action = event.target.getAttribute("data-rx-confirm-action");
if (action === "confirm") {
if (typeof settings.onConfirm === "function") {
settings.onConfirm();
}
window.RXPopup.close(popup, {
source: "confirm"
});
}
if (action === "cancel") {
if (typeof settings.onCancel === "function") {
settings.onCancel();
}
window.RXPopup.close(popup, {
source: "cancel"
});
}
});
window.RXPopup.open(popup, {
source: "builder-confirm"
});
return popup;
},
escape: function (value) {
var div = document.createElement("div");
div.textContent = value;
return div.innerHTML;
},
extend: function () {
var output = arguments[0] || {};
for (var i = 1; i < arguments.length; i++) {
if (!arguments[i]) {
continue;
}
for (var key in arguments[i]) {
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
output[key] = arguments[i][key];
}
}
}
return output;
}
};
/**
* Newsletter form helper
*/
var RXPopupNewsletter = {
init: function () {
document.addEventListener("submit", function (event) {
var form = event.target.closest("[data-rx-popup-newsletter]");
if (!form) {
return;
}
RXPopupNewsletter.handleSubmit(event, form);
});
},
handleSubmit: function (event, form) {
var ajax = form.getAttribute("data-rx-popup-newsletter-ajax");
if (ajax !== "true") {
return;
}
event.preventDefault();
var action = form.getAttribute("action");
var method = form.getAttribute("method") || "POST";
var messageBox = form.querySelector("[data-rx-popup-message]");
var submitButton = form.querySelector('[type="submit"]');
if (!action) {
this.showMessage(messageBox, "Form action is missing.", "error");
return;
}
var formData = new FormData(form);
if (submitButton) {
submitButton.disabled = true;
submitButton.classList.add("is-loading");
}
fetch(action, {
method: method,
body: formData,
credentials: "same-origin"
})
.then(function (response) {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.text();
})
.then(function () {
RXPopupNewsletter.showMessage(
messageBox,
"Thank you. Your request has been submitted.",
"success"
);
form.reset();
document.dispatchEvent(
new CustomEvent("rxPopupNewsletterSuccess", {
detail: {
form: form
}
})
);
})
.catch(function () {
RXPopupNewsletter.showMessage(
messageBox,
"Something went wrong. Please try again.",
"error"
);
document.dispatchEvent(
new CustomEvent("rxPopupNewsletterError", {
detail: {
form: form
}
})
);
})
.finally(function () {
if (submitButton) {
submitButton.disabled = false;
submitButton.classList.remove("is-loading");
}
});
},
showMessage: function (box, message, type) {
if (!box) {
return;
}
box.textContent = message;
box.className = "rx-popup-message rx-popup-message--" + type;
box.setAttribute("role", type === "error" ? "alert" : "status");
}
};
/**
* Auto initialize
*/
function bootRXPopup() {
window.RXPopup = RXPopup;
window.RXPopupBuilder = RXPopupBuilder;
RXPopup.init(window.rxPopupSettings || {});
RXPopupNewsletter.init();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", bootRXPopup);
} else {
bootRXPopup();
}
})();
Example HTML popup
<div
id="rx-newsletter-popup"
class="rx-popup"
data-rx-popup
data-rx-popup-delay="4000"
data-rx-popup-once="true"
data-rx-popup-frequency="168"
>
<button type="button" class="rx-popup__close" data-rx-popup-close aria-label="Close popup">
×
</button>
<div class="rx-popup__inner">
<h2 class="rx-popup__title">Join RX Health Updates</h2>
<p class="rx-popup__text">
Get simple medical education, health articles, and RX Theme updates.
</p>
<form data-rx-popup-newsletter data-rx-popup-newsletter-ajax="false">
<input type="email" name="email" placeholder="Your email address" required>
<button type="submit">Subscribe</button>
<div data-rx-popup-message></div>
</form>
</div>
</div>
Example trigger button
<button type="button" data-rx-popup-trigger="rx-newsletter-popup">
Open Popup
</button>
Example CSS starter
.rx-popup-overlay {
position: fixed;
inset: 0;
z-index: 9998;
background: rgba(0, 0, 0, 0.55);
opacity: 0;
visibility: hidden;
transition: opacity 0.25s ease, visibility 0.25s ease;
}
.rx-popup-overlay.is-active,
.rx-popup-overlay.is-visible {
opacity: 1;
visibility: visible;
}
.rx-popup {
position: fixed;
top: 50%;
left: 50%;
z-index: 9999;
width: min(92vw, 560px);
max-height: 90vh;
overflow: auto;
background: #fff;
color: #111;
border-radius: 16px;
box-shadow: 0 20px 80px rgba(0, 0, 0, 0.25);
transform: translate(-50%, -48%) scale(0.96);
opacity: 0;
visibility: hidden;
transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s ease;
}
.rx-popup.is-active,
.rx-popup.is-visible {
opacity: 1;
visibility: visible;
transform: translate(-50%, -50%) scale(1);
}
.rx-popup__inner {
padding: 32px;
}
.rx-popup__close {
position: absolute;
top: 12px;
right: 12px;
width: 36px;
height: 36px;
border: 0;
border-radius: 50%;
cursor: pointer;
font-size: 24px;
line-height: 1;
}
.rx-popup-open {
overflow: hidden;
}
Enqueue in functions.php
function rx_theme_enqueue_popup_chunk() {
wp_enqueue_script(
'rx-popup-chunk',
get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-026-popup.js',
array(),
'1.0.0',
true
);
}
add_action( 'wp_enqueue_scripts', 'rx_theme_enqueue_popup_chunk' );
This file is good for the advanced stage of RX Theme because it is modular, reusable, accessibility-aware, and can work with many future popup types without rewriting the whole system.