How to fix menu toggle double clicks issue?
Using Elemental Menu, many customers have reported an issue of the Mobile Menu Toggle button doesn’t work on the first touch when Delay JavaScript Execution is enabled. It’s hard to explain again and again so, in this article, we will explain in details about how it happens and how to fix it.
How delay JavaScript execution works?
Basically, Delay JavaScript Execution will delay the loading of external JavaScript files and inline JavaScript code until a certain point. For most caching plugins, it’s until there is a user interaction.
WP-Rocket’s Delay JavaScript Execution for example:
As you can see, after the page is loaded, only the wp-embed
script is loaded. Other scripts are only loaded after touching on the Menu Toggle button (a user interaction).
The wp-embed
script is excluded from Delay JavaScript Execution by default so it won’t be delayed. You can see the default scripts which are excluded by WP-Rocket here.
Why Menu Toggle doesn’t work on the very first touch?
As mentioned, all scripts are delayed until there’s a user interaction. So, if touching on the Menu Toggle is the very first user interaction, that interaction will only trigger the loading of the delayed scripts, the execution of those scripts is still being delayed until the second interaction. In other words, there’s no script available to handle the very first touch.
Technically, in JavaScript, a user interaction is an event. And to handle an event, JavaScript needs to know the target of that event and who is responsible for handling that event.
In the case of the Menu Toggle button, the process is like this:
- User: Touches the Menu Toggle button (the very first interaction).
- Browser: Who is responsible for that interaction? No one responses… Ignore the interaction.
- Caching Plugin: An interaction captured, it’s time to load the delayed scripts… done!
- Menu Script: I’m fully loaded. Looking for the Menu Toggle… OK, found it. Listening for interaction on that element.
- User: Touches the Menu Toggle again
- Browser: A touch interaction captured, who is responsible for that interaction?
- Menu Script: It’s me… toggles the Mobile Menu.
For more info about how JavaScript handles user interaction, please read this article.
That’s how it happens. But… isn’t it weird? Will someone just jump into a page and the very first action is to click on the Menu Toggle button? A normal user would go to a page, scroll down to look for something first. People who clicks on the Menu Toggle button immediately after a page loaded are likely testers and developers.
How to fix it?
There’re some solutions which have both cons and pros. It’s up to your preference.
Solution 1: Exclude the script handlers
The first solution is to exclude the relevant scripts from Delay JavaScript Execution.
If you’re using WP-Rocket, you can read more about the solution here.
Pros: Absolutely fixes the issue because the root cause is gone.
Cons: Not always works. It’s hard to exclude a script which has many dependencies. And excluding heavy/many scripts will ruin the purpose of Delay JavaScript Execution.
We don’t recommend to use this solution with Elemental Menu.
Solution 2: Trigger the second touch programmatically
Programmatically, JavaScript itself can simulate the touch action. So the trick is that we will use JavaScript to trigger the second touch right after users’s very first touch.
First, copy and paste the below code into your theme footer:
<script id="bypassDelayExecution">
function showElementalMenu(d) {
if (typeof elementorFrontend === "undefined" || !elementorFrontend.elementsHandler) {
setTimeout(() => d.target.closest(".emm13").click(), 100);
return;
}
d.stopImmediatePropagation();
let a = document.querySelector(".emm14"),
b = document.querySelector(".emm15");
d.currentTarget.setAttribute("aria-pressed", !0);
d.currentTarget.setAttribute("aria-expanded", !0);
d.currentTarget.classList.add("emm57");
b.classList.add("emm52");
a.style.display="block";
d.currentTarget.removeEventListener("click", showElementalMenu, !0);
}
window.addEventListener("DOMContentLoaded", () => {
let toggleBtn = document.querySelector(".emm13");
toggleBtn && toggleBtn.addEventListener("click", showElementalMenu, !0);
});
</script>
Then, exclude the bypassDelayExecution
from delay execution:
Pros: You can delay all scripts to achieve maximum performance. The bypassDelayExecution
script won’t affect your page speed.
Cons: Entrance animations won’t work because it requires some heavy scripts which have been delayed. Also, there will be some delay before the Mobile Menu starts showing. That delay = time to load the delayed scripts after the very first touch + time to register event handlers after the delayed scripts fully loaded.
You may try this solution if your Mobile Menu does not have any animations.
Solution 3: Fake a user interaction
The trick is that we will timing the time when a page is fully loaded and trigger a fake user interaction to force Caching Plugins to load delayed scripts immediately.
First, copy and paste the following script into your theme footer:
<script id="timingDelayExecution">
// 500 milliseconds after a page loaded, trigger a fake user interaction.
// If your site is fast, adjust the 500 milliseconds accordingly.
window.onload = () => setTimeout(() => window.dispatchEvent(new Event('touchend')), 500);
</script>
Then, exclude the timingDelayExecution
from delay execution:
Pros: You can achieve maximum performance by delaying all scripts. Entrance animations works perfectly.
Cons: Until now, we haven’t found any issue with this solution.
Conclusion: Those are three ways to fix the double clicks issue on the Menu Toggle button when Delay JavaScript Execution is enabled. We recommend the third one but you may do more tests with your site to find out the best solution for you.
If you have any issue, let us know in the comment section.