
A browser-based editor for Shields.io static badges, with logos from Simple Icons. You type straight onto a large live b
A browser-based editor for Shields.io static badges, with logos from Simple Icons. You type straight onto a large live badge, pick a brand icon visually, and copy the result as Markdown, HTML or a plain URL.
It runs entirely in the browser: no backend, no accounts, and nothing to deploy beyond static files.
Live site: https://khryz-navarro.github.io/shieldiomaker/
flat, flat-square, plastic, for-the-badge and social. The editable badge imitates each one, including Shields' rule of dark text on light colors.#555555) and has a reset.img.shields.io badge sits next to the snippet, so what you see is what you paste., wrapped in a link when one is set.<img>, wrapped in <a> when a link is set.<object> embed so each half keeps its own link. It appears only when both links are set.Everything happens in src/badge.js, a small set of pure functions covered by tests.
Badges use the Shields.io static badge endpoint:
https://img.shields.io/badge/<label>-<message>-<color>?<options>
Escaping. In the path, - and _ are separators, so they are doubled (--, __). Spaces become _, and everything is URL-encoded. For example, built-with / my_app v1 becomes built--with-my__app_v1.
No label. With an empty label, the path is just <message>-<color>.
Options are added only when they differ from the defaults:
| Option | When it's added |
|---|---|
style |
Any style other than flat |
logo |
A Simple Icons slug (e.g. react) or a custom logo's data URI |
logoColor |
A Simple Icons logo is set. It's left out for custom logos, because Shields ignores it there. |
labelColor |
A custom label color is set |
link (repeated) |
Any link is set. The first link is the left half, the second is the right. An empty value leaves that half unlinked. |
The editable badge uses Shields' own brightness rule: (r·299 + g·587 + b·114) / 255000 ≥ 0.69 gets dark text (#333), otherwise white.
Shields.io's logo option accepts a Simple Icons slug or a base64 data URI, but not a link to an image. Uploaded files are therefore read in the browser and embedded as data:image/svg+xml;base64,… or data:image/png;base64,….
The 6 KB limit comes from testing img.shields.io directly. A ~6 KB SVG (an 8,189-character URL) rendered, while a ~12 KB one was rejected with HTTP 431, meaning the request was too large. Files with an empty MIME type fall back to their .svg or .png extension.
Markdown and <img> can only make the whole badge one link, so those outputs use the message link (or the label link when it is the only one). Separate links per half only work when the SVG is embedded with <object>, and GitHub strips <object> from READMEs.
^20.19.0 or >=22.12.0 (required by Vite 8)git clone https://github.com/Khryz-Navarro/shieldiomaker.git
cd shieldiomaker
npm install
npm run dev
Then open the local URL Vite prints (usually http://localhost:5173).
npm run build
The static site is written to dist/. Preview the build locally with npm run preview.
Every push to master runs .github/workflows/deploy.yml. It installs dependencies, runs the tests, builds, and publishes dist/ to GitHub Pages. The site is served from /shieldiomaker/, which is set as base in vite.config.js; change it if the repo is renamed or hosted elsewhere.
| Command | What it does |
|---|---|
npm run dev |
Starts the Vite dev server with hot reload |
npm run build |
Builds the production site into dist/ |
npm run preview |
Serves the production build locally |
npm run lint |
Lints the source with Oxlint |
node --test src/badge.test.js |
Runs the unit tests for the badge helpers (Node's built-in test runner) |
shieldiomaker/
├── index.html Page shell
├── public/
│ └── favicon.svg
├── src/
│ ├── main.jsx React entry point
│ ├── App.jsx The whole UI: badge editor, callouts, icon picker, output, footer
│ ├── badge.js Pure helpers: badge URL, text color, custom logo checks
│ ├── badge.test.js Tests for badge.js (node --test)
│ └── index.css Styles and design tokens (light and dark)
simple-icons 16 for icon titles, slugs, brand colors and SVG pathsnode:test for testslogo=<slug> against its own copy of Simple Icons, which can lag behind the bundled package, so a very new icon may not render yet.<object>.Released under the MIT License.
Khryz Navarro
© 2026 Khryz Navarro. All rights reserved.
No updates yet.
Building a dev tool or hiring developers? Get seen here. Become our Sponsor
Building a dev tool or hiring developers? Get seen here. Become our Sponsor