<nav aria-label="Skip links" class="skip-menu">
<a class="site-skip" href="#main-content">Skip to content</a>
</nav>
<main class="container" id="main-content">
<div class="row mt-2 mb-5">
<div class="col-md-6 offset-md-3 d-flex align-items-center flex-column">
<p class="mb-4 lead">Single button with attached multiple event handlers</p>
<button type="button" id="actionButton" class="btn btn-primary mb-4">Action</button>
<div id="results"></div>
</div>
</div>
</main>
html,
body {
height: 100%;
width: 100%;
}
body {
background: #fff;
color: #000;
font-family: "Helvetica Neue", "Segoe UI", Helvetica, Arial, "Lucida Grande",
sans-serif;
font-weight: 400;
font-size: 1em;
padding: 0 1em 1em 1em;
}
p {
margin-bottom: 1rem;
}
@media (max-width: 575.98px) {
h1 {
text-align: center;
}
}
button {
box-shadow: 0 4px 4px rgba(8 8 8 / 8%), 0 1px 2px rgba(8 8 8 / 20%),
inset 0 6px 12px rgba(255 255 255 / 12%),
inset 0 1px 1px rgba(255 255 255 / 20%);
}
.skip-menu a {
left: 50%;
transform: translate(-50%, 0);
background-color: #0070d1;
border-radius: 0;
box-shadow: 0px 0px 18px -1px rgb(0 0 0 / 32%);
color: #fff;
display: block;
padding: 1rem;
position: absolute;
text-align: center;
top: -7rem;
transition: top 0.3s ease-in-out;
z-index: 999999;
}
.skip-menu a:focus {
background-color: #0070d1;
color: #fff;
outline-color: #0070d1;
top: 4px;
}
(function () {
const resultsElement = document.querySelector("#results");
const actionButton = document.querySelector("#actionButton");
let processedEvent = false;
const redispatchEvent = (event, target) => {
// Uncaught (in promise) DOMException: Failed to execute 'dispatchEvent' on 'EventTarget': The event is already being dispatched.
try {
target.dispatchEvent(event);
} catch (e) {
// silence
}
processedEvent = false;
target.disabled = false;
};
const onClickFirstHandler = async (event) => {
const target = event.target;
if (
processedEvent ||
target === null ||
(target.nodeName.toLowerCase() === "button" &&
target.type !== "button") ||
event.type !== "click"
) {
return;
}
resultsElement.insertAdjacentHTML(
"beforeend",
"<p>First event handler. Waiting 3 seconds to finish the asynchronous operation.</p>"
);
processedEvent = true;
target.disabled = true;
event.stopPropagation();
const action = () => {
return new window.Promise((resolve, reject) => {
window.setTimeout(() => {
console.log("[onClickFirstHandler]", event);
processedEvent = true;
resolve();
}, 3000);
});
};
await action();
redispatchEvent(event, target);
};
const onClickSecondHandler = (event) => {
console.log("[onClickSecondHandler]", event);
resultsElement.insertAdjacentHTML(
"beforeend",
"<p>Second event handler</p>"
);
};
const onClickThirdHandler = (event) => {
console.log("[onClickThirdHandler]", event);
resultsElement.insertAdjacentHTML(
"beforeend",
"<p>Third event handler</p>"
);
};
const addEventListenerOptions = {
capture: true
};
actionButton.addEventListener(
"click",
onClickFirstHandler,
addEventListenerOptions
);
actionButton.addEventListener("click", onClickSecondHandler);
actionButton.addEventListener("click", onClickThirdHandler);
// Google Analytics
const loadGTM = () => {
const gtmScript = document.createElement("script");
const documentHead = document.head;
gtmScript.src = "https://www.googletagmanager.com/gtag/js?id=G-JTTSY0KNFH";
gtmScript.type = "text/javascript";
gtmScript.async = true;
gtmScript.onload = () => {
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "G-JTTSY0KNFH");
};
documentHead.insertBefore(gtmScript, documentHead.firstChild);
};
let url = new URL(window.location.href);
if (url.protocol !== "file:") {
loadGTM();
}
})();
This Pen doesn't use any external JavaScript resources.