Skip to content

Add Scroll Progress Bar

1 min read

This recipe shows how to display a fixed scroll progress bar at the top of every page in Starlight.

  1. Create a new Astro component src/components/ScrollProgress.astro. This component calculates the scroll percentage and updates a bar’s width.

    src/components/ScrollProgress.astro
    <div id="scroll-progress" class="scroll-progress"></div>
    <script>
    function updateScrollProgress() {
    const progressLine = document.getElementById("scroll-progress");
    if (!progressLine) return;
    const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
    const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
    const scrolled = height > 0 ? (winScroll / height) * 100 : 0;
    progressLine.style.width = scrolled + "%";
    }
    window.addEventListener("scroll", updateScrollProgress);
    updateScrollProgress();
    document.addEventListener('astro:after-swap', updateScrollProgress);
    </script>
    <style>
    .scroll-progress {
    position: fixed;
    top: 0;
    left: 0;
    width: 0%;
    height: 3px;
    background-color: var(--sl-color-accent-high);
    z-index: 1000;
    transition: width 0.1s ease-out;
    pointer-events: none;
    }
    </style>
  2. Create a new component src/components/Header.astro to override the default Starlight Header:

    src/components/Header.astro
    ---
    import type { Props } from "@astrojs/starlight/props";
    import Default from "@astrojs/starlight/components/Header.astro";
    import ScrollProgress from "./ScrollProgress.astro";
    ---
    <ScrollProgress />
    <Default {...Astro.props} />
  3. Tell Starlight to use your custom Header in your config:

    astro.config.mjs
    import { defineConfig } from "astro/config";
    import starlight from "@astrojs/starlight";
    export default defineConfig({
    integrations: [
    starlight({
    components: {
    Header: "./src/components/Header.astro",
    },
    }),
    ],
    });