An action page with a progress bar and a link
Imagine this was a campaign page on your main website.
The number on the progress bar here is live-updated from a published Impact Stack page with the current number of signatures. See the Impact Stack page here.
You could place the progress bar and button anywhere on your main website. You could edit the text around the progress bar to say anything you wanted.
The 'Take Action' button on this page is a standard link that goes straight to the Impact Stack page with no prefilling of the form.
Working demo ⤵︎
How to do it
Here's some basic code to get you started. Most organisations would need a web developer to pick this up and adapt it for your needs and your website technology. If you put it on your main website it would likely inherit a lot of the existing styling, but we'd still expect you to need to do some work to make sure it looked on-brand for you.
It can work because every Impact Stack action has a separate,
published page with some JSON that shows the current number of
signatures. This page has a URL using the format /node/{nodeID}/polling
For example, the number at pgbar → pgbar_default at this URLhttps://demo2.impact-stack.org/node/216/polling
See the Progress Bar Code
<label for="progressBar"> <span id="signaturesText">0 people have</span> taken action so far</label><!-- You could also use some nested <div>s --><progress id="progressBar" max="100" value="0"></progress>
<script> // Adjust the domain as needed const domain = "https://demo2.impact-stack.org";
// An array of Impact Stack node IDs. Can be multiple eg. ["216", "224"] and it will sum the total signatures of all of them const nodeIDs = ["216"];
// Adjust the locale if needed. This is for the number formatting const locale = "en-GB";
document.addEventListener("DOMContentLoaded", () => { // You might want to hide the progress bar and only show it again once the data is fetched // You also might want to animate the progress bar like we do on Impact Stack
updateProgressBar();
/** * Update a progress bar based on the number of signatures fetched from Impact Stack * Changes the text of the progress bar and the value of the progress bar based on the number of signatures * The text of the progress bar is updated to "1 person has" or "N people have" depending on the number of signatures * The maximum value of the progress bar is updated to the number of signatures divided by 0.9 so the progress bar is always 90% full */
async function updateProgressBar() { const signaturesText = document.getElementById("signaturesText"); // Adjust the selector if needed const progressBar = document.querySelector("progress#progressBar"); // Adjust the selector if needed
if (signaturesText === null || progressBar === null || progressBar instanceof HTMLProgressElement === false) { console.error("Signatures text or progress bar not found."); return; }
const signaturesNumber = await fetchSignatureNumberFromImpactStack( domain, nodeIDs
);
if (signaturesNumber === null) { console.log("Failed to fetch number"); return; }
// Formatting the number of signatures to display const formattedSignaturesNumber = new Intl.NumberFormat( locale ).format(signaturesNumber);
if (signaturesNumber === 1) { signaturesText.innerText = `${formattedSignaturesNumber} person has`; // Adjust the text if needed } else { signaturesText.innerText = `${formattedSignaturesNumber} people have`; // Adjust the text if needed }
progressBar.max = signaturesNumber / 0.9; // This will set the maximum value so that the progress bar is always 90% full progressBar.value = signaturesNumber;
}
/** * Fetches the signature number from Impact Stack from an array of node IDs * * @param {string} domain - The Impact Stack domain * @param {string[]} nodeIDs - An array of node IDs to fetch the signature number for * @returns {number|null} The signature number, or null if an error occurred */
async function fetchSignatureNumberFromImpactStack(domain, nodeIDs) { let signaturesNumber = 0;
for (const nodeID of nodeIDs) { const url = `${domain}/node/${nodeID}/polling`;
try { const response = await fetch(url);
if (!response.ok) { console.error(`HTTP error! status: ${response.status}`); return null; }
const data = await response.json(); const number = data.pgbar.pgbar_default[0]; // The route to the data signaturesNumber += number; } catch (error) { console.error( `There was a problem fetching the data from ${url}: ${error}` ); } }
return signaturesNumber; }
});</script>
<style> /* This would be very different if you use nested <div>s instead of the <progress> element */ progress { /* Remove default styling */ -webkit-appearance: none; -moz-appearance: none; appearance: none;
/* Remove border in Firefox */ border: none;
/* Dimensions */ width: 280px; height: 40px;
}
/* Background bar (Chrome/Safari/Edge) */ progress::-webkit-progress-bar { background-color: #f3f4f6; border-radius: 4px; box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); }
/* Value bar (Chrome/Safari/Edge) */ progress::-webkit-progress-value { background-color: #90c92a; border-radius: 4px; transition: width 0.3s ease; }
/* Value bar (Firefox) */ progress::-moz-progress-bar { background-color: #90c92a; border-radius: 4px; transition: width 0.3s ease; }</style>