Progress

The agnostic-astro package utilizes XElement under-the-hood in order to provide build-time Astro components. These build-time components will help your project get closer to realizing a mostly no client-side runtime…if you do it right, this should mean an all-green 100% Lighthouse performance score! Leverage the benefits of Islands architecture by sending mostly server built agnostic-astro components. Then, sprinkle client-hydrated ones only as needed.

Usage

Ensure you've installed and setup the AgnosticUI Astro integration which will import the required common.min.css onto your page:

npm i @astro/agnostic-astro

Then add the integration to your astro.config.mjs (you may need to run Astro with experimental integrations flag astro dev --experimental-integrations):

import { defineConfig } from 'astro/config';
import agnosticAstro from '@astrojs/agnostic-astro';
export default defineConfig({
  integrations: [agnosticAstro()]
});

Then you can import Astro Progress component:

import AgProgress from 'agnostic-astro/Progress.astro';

Here's the agnostic-astro Progress component in use:

<AgProgress class="mbs24 progress-el" max={100} value={0} />

Here's how you might implement the above functionality using only platform JavaScript:


  // This is just a demo of how you might control the progress
  // with your own application code
  const progressElement = document.querySelector('.progress-el');
  const playButton = document.querySelector('.start');
  const stopButton = document.querySelector('.stop');
  let requestAnimationID;
  let progress = 0;

  // Increments progress by 1 unit then issues RAF request
  const step = () => {
    playButton.disabled = true;
    stopButton.disabled = false;
    progress += 1;
    progressElement.setAttribute('value', progress.toString());
    if (progress === 100) {
      playButton.disabled = false;
      stopButton.disabled = true;
    } else if (progress < 100) {
      requestAnimationID = requestAnimationFrame(step);
    }
  }

  // Calls step and stores the RAF ID
  requestAnimationID = requestAnimationFrame(step);

  // Attaches the start aka play button click handler
  playButton.addEventListener('click', () => {
    // Circle back to zero if at end
    if (progress >= 100) {
      progress = 0;
    }
    requestAnimationID = requestAnimationFrame(step)
  })

  // Attaches the stop button click handler
  stopButton.addEventListener('click', () => {
    if (requestAnimationID) {
      cancelAnimationFrame(requestAnimationID)
      requestAnimationID = undefined
      // Re-enable the Play button
      playButton.disabled = false
      stopButton.disabled = true
    }
  })