I use an accordion or tabs. When clicking on a tab, I want to display a map or something that require a big javascript file to load.
To not load the big javascript when it is not needed, I want to load it only when the tab is clicked.
How can I do that? I've created a good starting point with accordion and a click event.
window.addEventListener('DOMContentLoaded', () => {
document.querySelector('[data-trigger]').addEventListener('click', () => {
console.log('Load script from file');
// CDN example - https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/1.12.0/mapbox-gl.js
});
});
ul {
list-style: none;
margin: 0;
padding: 0;
}
label {
display: flex;
align-items: center;
}
label:before {
content: '';
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M13.172 12l-4.95-4.95 1.414-1.414L16 12l-6.364 6.364-1.414-1.414z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
width: 24px;
height: 24px;
}
input[type=checkbox] {
display: none;
}
input[type=checkbox]:checked ~ h2 label:before {
transform: rotate(90deg);
}
p {
display: none;
}
input[type=checkbox]:checked ~ h2 ~ p {
display: block;
}
<ul>
<li>
<input type="checkbox" id="faq-1">
<h2 data-trigger>
<label for="faq-1">Click to load map</label>
</h2>
<p>Gummies marzipan croissant chupa chups.</p>
</li>
<li>
<input type="checkbox" id="faq-2">
<h2>
<label for="faq-2">Something else</label>
</h2>
<p>Cookie bear claw carrot cake croissant.</p>
</li>
</ul>
You could dynamically create a script tag and add it to the document whenever the button is pressed. This will trigger the script to immediately be loaded. With the onload
callback you can run your code, like creating a map, the moment the script has actually loaded.
Do add { once: true }
as the third parameter for addEventListener
as it will ensure that the trigger can only be clicked once and won't be able to append the script more than once.
function createMap() {
const map = new mapboxgl.Map({
...
});
}
window.addEventListener('DOMContentLoaded', () => {
document.querySelector('[data-trigger]').addEventListener('click', () => {
console.log('Load script from file');
const script = document.createElement('script');
script.id = 'mapboxgljs';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/1.12.0/mapbox-gl.js'
script.async = true;
script.onload = function() {
console.log('script loaded, you can use it now.');
createMap();
}
document.body.append(script);
}, { once: true }); // Make sure that the button can only be pressed once.
});
As you're comfortable with only supporting modern browsers, you could use the dynamic import()
function to load the file:
window.addEventListener('DOMContentLoaded', () => {
document.querySelector('[data-trigger]').addEventListener('click', async() => {
const module = await import('https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/1.12.0/mapbox-gl.js');
console.log(`module is loaded: ${Object.keys(mapboxgl)}`);
});
});
ul {
list-style: none;
margin: 0;
padding: 0;
}
label {
display: flex;
align-items: center;
}
label:before {
content: '';
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M13.172 12l-4.95-4.95 1.414-1.414L16 12l-6.364 6.364-1.414-1.414z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
width: 24px;
height: 24px;
}
input[type=checkbox] {
display: none;
}
input[type=checkbox]:checked~h2 label:before {
transform: rotate(90deg);
}
p {
display: none;
}
input[type=checkbox]:checked~h2~p {
display: block;
}
<ul>
<li>
<input type="checkbox" id="faq-1">
<h2 data-trigger>
<label for="faq-1">Click to load map</label>
</h2>
<p>Gummies marzipan croissant chupa chups.</p>
</li>
<li>
<input type="checkbox" id="faq-2">
<h2>
<label for="faq-2">Something else</label>
</h2>
<p>Cookie bear claw carrot cake croissant.</p>
</li>
</ul>
import()
returns a promise which is resolved on successful fetch, and resolves immediately on subsequent calls (in my testing), so you wouldn't have to deal with that specifically.
For your specific mapbox-gl
script, the value returned won't be useful, as the script isn't written as an ES6 module, but the side-effects of the script running will be in place (in this case, the mapboxgl
variable being assigned onto globalThis
). In scenarios where the loaded script is a module (using export
correctly), you can use the resolved value directly to avoid polluting the global namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With