Skip to content

Instantly share code, notes, and snippets.

@maiah
Created July 14, 2026 23:41
Show Gist options
  • Select an option

  • Save maiah/841d7dc651894d4b47b4b587be5f2806 to your computer and use it in GitHub Desktop.

Select an option

Save maiah/841d7dc651894d4b47b4b587be5f2806 to your computer and use it in GitHub Desktop.
Astro Top Bar Loader
---
// src/components/ProgressBar.astro
---
<div id="top-progress-bar"></div>
<style is:global>
#top-progress-bar {
position: fixed;
top: 0;
left: 0;
width: 0%;
height: 3px;
background-color: #ff0000; /* YouTube Red - change to your brand color */
z-index: 9999;
pointer-events: none; /* Ensure it doesn't block clicks */
opacity: 0;
transition: width 0.2s ease, opacity 0.3s ease;
}
</style>
<script>
let progressInterval: number | ReturnType<typeof setInterval>;
// Start the loading bar when navigation begins
document.addEventListener('astro:before-preparation', () => {
const progressBar = document.getElementById('top-progress-bar');
if (!progressBar) return;
// Reset state
progressBar.style.transition = 'none';
progressBar.style.width = '0%';
progressBar.style.opacity = '1';
// Force DOM reflow so the transition applies on the next frame
void progressBar.offsetWidth;
progressBar.style.transition = 'width 0.4s ease, opacity 0.3s ease';
let width = 10;
progressBar.style.width = `${width}%`;
// Create the "trickle" effect by incrementally increasing width
progressInterval = setInterval(() => {
// Don't go past 90% until the page actually loads
if (width >= 90) {
clearInterval(progressInterval);
} else {
width += Math.random() * 5 + 2;
progressBar.style.width = `${width}%`;
}
}, 300);
});
// Finish and hide the loading bar when the new page is ready
document.addEventListener('astro:page-load', () => {
const progressBar = document.getElementById('top-progress-bar');
if (!progressBar) return;
// Stop the trickling
clearInterval(progressInterval);
// Shoot to 100%
progressBar.style.width = '100%';
// Wait for the 100% animation to finish, then fade out
setTimeout(() => {
progressBar.style.opacity = '0';
// Reset width after it's invisible so it's ready for next time
setTimeout(() => {
progressBar.style.width = '0%';
}, 300);
}, 400);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment