Horizontal progress indicator for your Starlight site

In this post, we would like to show you how FrostyBee created a clean horizontal progress indicator for Starlight sites.

Prerequisites

You will need to have an existing Starlight website.

Create the progress indicator component

Let's create a new component called ProgressIndicator.astro in the src/components/ directory. This component will be responsible for rendering the progress indicator.

We create a container which spans across the whole width with the progress bar inside. The width of the inner is the updated whenever the user scrolls (and when the page loads) to reflect the current scroll position.






window.addEventListener("scroll", function () {
updateProgressScroll();
});
window.addEventListener("load", function () {
updateProgressScroll();
});
function updateProgressScroll() {
if (document) {
const progressScroll = document.getElementById("progress-scroll");
if (progressScroll) {
var scrollTop = window.scrollY || document.documentElement.scrollTop;
var scrollHeight =
document.documentElement.scrollHeight - window.innerHeight;
var progress = (scrollTop / scrollHeight) * 100;
progressScroll.style.width = progress + "%";
}
}
}



html:is(:not([data-has-hero]), [data-has-sidebar], [data-has-toc]) .progress-scroll-container {
position: fixed;
top: var(--sl-nav-height);
left: 0;
height: 0.25rem;
width: 100%;
background-color: transparent;
z-index: 3;
}
#progress-scroll {
height: 100%;
width: 0px;
background-color: var(--sl-color-accent-high);
}



#starlight__on-this-page--mobile {
margin-top: 0.25rem;
}


In the hidden lines is the styling which makes sure that the progress bar looks like a typical progress bar. It is also suited to Starlight because the bar is automatically hidden when the site has no sidebar and table of contents, but a hero element as most landing pages do.

One thing to point out is what the global CSS (line 45 - almost at the end of the file) does: It pushes the mobile table of contents dropdown menu down to create more whitespace to the progress bar. This is a personal preference and you can remove it if you want.

Starlight Override

Now we can use this component in a Starlight override. In this case it makes sense to override the Header.astro component like this:

---
import Default from "@astrojs/starlight/components/Header.astro";
import ScrollIndicator from "./ScrollIndicator.astro";
---

<Default><slot /></Default>
<ScrollIndicator />

Do not forget to add this component override to your astro.config.mjs file:

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';

export default defineConfig({
integrations: [
starlight({
title: 'My Docs with a Progress Indicator',
components: {
// Override the default `Header` component.
Header: './src/components/Header.astro',
},
}),
],
});

Source Code

You can find the whole project code on GitHub and in this Stackblitz example.

Conclusion

With this setup, the progress indicator will be displayed on every page (except landing pages) of your Starlight site. 🥳

You can also check out FrostyBee's Starlight Scroll To Top plugin which also supports a built in Progress Ring since version 0.3.1. 🙌