While developing the my platforms (my version of
linktree), I realised my initial loading mechanism, which relied on
my customised docReady
, was not cutting it. It missed out
on crucial elements like external images and API calls, leading to an
inconsistent loading experience. I knew I needed a more comprehensive
solution—one that would track every resource seamlessly, ensuring users
experience a smooth, uninterrupted progress bar.
Step-by-Step Breakdown of the Solution
1. Dynamically Track All Resources: Images and APIs
The first thing I addressed was dynamically collecting all resources that needed to load—images, API calls, and any external assets.
Code Snippet: 1
2
3const getAllImages = () => {
return [...document.querySelectorAll('img')].map(img => img.src);
};
2. Incremental Progress Calculation
To ensure smooth progress tracking, I calculated the progress percentage based on the total number of resources (images + API calls). For every loaded resource, the progress is updated.
Key Concept:
- Total Resources: Total number of images + API calls.
- Loaded Items: Track loaded resources and update the percentage accordingly.
Code Snippet: 1
2
3
4const updateLoadingProgress = () => {
const percent = (loadedItems / totalItems) * 100;
updateLoadingProgressSmoothly(percent);
};
3. Smooth Progress with Delays
For a polished user experience, I added delays and smaller steps to the progress increments. This ensures that even with a fast network, the bar doesn't jump directly to 100%.
Key Concept: Adjust the delay based on progress—slower increments at the start, faster towards the end, but always smooth.
Code Snippet: 1
2
3
4
5
6
7
8
9
10
11const updateLoadingProgressSmoothly = (targetPercent, delay = 50) => {
const step = (targetPercent - currentPercent) / 100;
const interval = setInterval(() => {
if (currentPercent < targetPercent) {
currentPercent += step;
document.getElementById('loading-bar').style.width = `${currentPercent}%`;
} else {
clearInterval(interval);
}
}, delay);
};
4. Tracking API Calls
In addition to images, I also needed to track API calls. I
implemented a simple wrapper around fetch()
to ensure each
call was accounted for in the progress.
Code Snippet: 1
2
3
4
5
6
7const trackedFetch = async (url) => {
const apiPromise = fetch(url);
await apiPromise;
loadedItems++;
updateLoadingProgress();
return apiPromise;
};
5. Debugging for Accurate Progress Tracking
Throughout the implementation, I used logging to debug issues like overshooting the progress (going beyond 100%) or not reaching 100%. Debugging helped fine-tune the logic for a more reliable progress bar.
Code Snippet: 1
log(`${loadedItems}/${totalItems} - Loading progress: ${percent}%`);
6. Hiding the Loading Screen
Once all resources are loaded and the progress bar reaches 100%, I smoothly hide the loading screen to reveal the page.
Code Snippet: 1
2
3
4
5
6if (currentPercent >= 100) {
setTimeout(() => {
document.getElementById('loading-screen').style.opacity = "0";
document.getElementById('loading-screen').style.zIndex = "-999";
}, 300);
}
My Code
1 | let loadedItems = 0; |
Preview

Final Thoughts
Creating a dynamic loading bar might seem like a small detail, but I've found that it makes a huge difference in how smooth and polished the overall experience feels for users. Whether it's tracking images, API calls, or other external assets, having everything run seamlessly creates that subtle, yet important, sense of reliability and care.
Of course, this is just one approach, and I know it's definitely NOT the best or only way to do it. I'm always learning, and I'm open to feedback from anyone who's more experienced! 🙌
I'm sure there are tons of ways to make this even better, and I'd love to hear how the pros out there tackle similar challenges.
If you've done something similar or have tips to share, feel free to drop a comment below. Let's learn from each other and keep improving our craft! 🤩
References
- https://gsap.com/community/forums/topic/12201-draw-svg-plugin-to-animate-a-dashed-line/
- https://codepen.io/MAW/pen/zGXvWW