SWHarden.com

The personal website of Scott W Harden

GitHub Repository Badge

What I learned creating a github repo stats badge using HTML and Vanilla JS

I created a badge to dynamically display stats for any public GitHub repository using HTML and Vanilla JavaScript. I designed it so anyone can have their own badge by copying two lines of HTML into their website.

I don’t write web frontend code often, so after getting this idea I decided to see how far I could take it. I treated this little project as an opportunity to get some experience exploring a stack I don’t interact with often, and to see if I could take it all the way to something that would look nice and scale infinitely for free. This article documents what I learned along the way

<!-- paste anywhere in your site -->
<a href="http://github.com/USER/REPO" id="github-stats-badge">GitHub</a>
<script src="https://swharden.github.io/repo-badge/badge.js" defer></script>

How it Works

Example Fetch

I expect the HTTP request to return a JSON document with a tag_name element, but if not I build my own object containing this object (filed with dummy data) and pass it along.

The display code (which sets the text, increases opacity, and sets the link) doesn’t actually know whether the request succeeded or failed.

This is how I ensure the badge is always left in a presentable state.

fetch(`https://api.github.com/repos/${user}/${repo}/releases/latest`)
    .then(response => { 
        return response.ok ? response.json() : { "tag_name": "none" };
    })
    .then(data => {
        const tag = document.getElementById('github-stats-badge--tag');
        tag.getElementsByTagName("span")[0].innerText = data.tag_name;
        tag.style.opacity = 1;
        tag.href = repoLinkUrl + "/releases";
    });

Fading

I don’t use CSS fading that often, but I found it produced a fantastic result here. Here’s the magic bit of CSS that enables fading effects as JavaScript twiddles the opacity

#github-stats-badge a {
    color: black;
    text-decoration: none;
    opacity: 0;
    transition: opacity .5s ease-in-out;
}

#github-stats-badge a:hover {
    color: #003366;
}

SVG Icons

GitHub has official MIT-licensed icons available as SVG files. These are fantastic because you can view their source and it’s plain text! You can copy that plain text directly into a HTML document, or in my case wrap it in JavaScript so I can serve it dynamically.

I store the path attribute contents as a JavaScript string like this

const githubStatusBadge_tagPath = "M2.5 7.775V2.75a.25.25 0 01.25-.25h5.025a.25.25 0 01.177.073l6.25 \
    6.25a.25.25 0 010 .354l-5.025 5.025a.25.25 0 01-.354 0l-6.25-6.25a.25.25 0 01-.073-.177zm-1.5 0V2.75C1 \
    1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 010 2.474l-5.026 5.026a1.75 \
    1.75 0 01-2.474 0l-6.25-6.25A1.75 1.75 0 011 7.775zM6 5a1 1 0 100 2 1 1 0 000-2z";

Then I create a function to build a SVG image from a path

function githubStatusBadge_createSVG(svgPath) {
    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
    svg.setAttribute('width', '16');
    svg.setAttribute('height', '16');
    svg.setAttribute('viewBox', '0 0 16 16');
    svg.style.verticalAlign = 'bottom';
    svg.style.marginRight = "2px";

    const path = document.createElementNS("http://www.w3.org/2000/svg", 'path');
    path.setAttribute('fill-rule', 'evenodd');
    path.setAttribute('d', svgPath);
    svg.appendChild(path);

    return svg;
}

Note that the NS method and xmlns attribute are critical for SVG elements to work in the browser. For more information check out Mozilla’s Namespaces crash course .

Minification

The non-minified plain-text JavaScript file is less than 8kb. This could be improved by minification and/or gzip compression, but I may continue to choose not to do this.

I appreciate HTML and JS which is human readable, especially when it was human-written by hand. Perhaps a good compromise would be to offer badge.js and badge.min.js, but even this would add complexity by necessitating a build step which is not currently required.

GitHub Pages

I organized this project so it could be served using GitHub Pages. Basically you just check a box on the GitHub repository settings page, then docs/index.html will be displayed when you go to USER.github.io/REPO in a browser. Building/publishing is performed automatically using GitHub Actions, and it works immediately without having to manually create a workflow yaml file.

Although GitHub pages supports a fancy markdown-based flat-file static website generation using Jekyll, I chose to create a project page using hand-crafted HTML, CSS, and Vanilla JS with no framework of build system. Web0 for the win!

GitHub stores and serves the content (with edge caching) so I’m protected in the unlikely case where this project goes viral and millions of people start downloading my JavaScript file. GitHub will scale horizontally as needed to infinity to meet the demand from increased traffic, and all the services I’m using are free.

New Website Checklist

Although the project page is simple, I wanted it to look nice. There are so many things to consider when making a new webpage! Here are a few that make my list, and most of them don’t apply to this small one-page website but I thought I’d share my whole list anyway.

Here’s the Open Graph banner I came up with:

Conclusions

Altogether the project page looks great and the badge seems to function as expected! I’ll continue to watch the repository so if anyone opens an issue or creates a pull request offering improvements I will be happy to review it.

This little Vanilla JS project touched a lot of interesting corners of web frontend development, and I’m happy I got to explore them today!

If you like this project, give it a star! 🌟

Resources