Build badge in React without SVG and no dependencies

Complete code on Codesandbox.io

Illia Zub
SerpApi
3 min readAug 11, 2020

--

Complete code on Codesandbox.io

We at SerpApi show integration test results on documentation pages. Anyone can browse source code of our RSpec files and it’s output. There’s a build badge on all documentation pages which points to the page with the list of test files. Each test file also displays build badge.

Here how it works on our documentation pages.

An example of build badges on SerpApi documentation pages
An example of build badges on SerpApi documentation pages

We started with Shields.io, but then implemented badges manually in React without SVG and dependencies. Complete code on Codesandbox.io.

Badge component

import React from "react";
import "./BuildBadge.css";
function BuildBadge({ status, summary, page_url }) {
let spinner;
if (status === "loading") {
spinner = <span className="loader" />;
}
return (
<div className="build-badge-container">
<a href={page_url}>
<div className="badge-name">build</div>
<div className={`badge-status ${status}`}>
{spinner}
<span>{summary}</span>
</div>
</a>
</div>
);
}

Badge styles

/* Thanks to https://shields.io/category/build for inspiration */
.build-badge-container {
height: 20px;
min-width: 200px;
margin: 2px 0;
}
.badge-name,
.badge-status {
display: inline-block;
height: 18px;
color: #fff;
font-family: Verdana, DejaVu Sans, sans-serif;
font-size: 11px;
line-height: 1.538;
letter-spacing: 0px;
text-shadow: 0px 1px rgba(1, 1, 1, 0.3);
}
.badge-name {
background: rgb(95, 95, 95);
background: linear-gradient(
180deg,
rgba(95, 95, 95, 1) 0%,
rgba(78, 78, 78, 1) 100%
);
border-radius: 3px 0px 0px 3px;
padding: 2px 4px 0px 6px;
}
.badge-status {
border-radius: 0px 3px 3px 0px;
padding: 2px 6px 0px 4px;
}
.badge-status.loading {
background: rgb(223, 179, 23);
background: linear-gradient(
180deg,
rgba(223, 179, 23, 1) 0%,
rgba(206, 162, 6, 1) 100%
);
}
.badge-status.success {
background: rgb(223, 179, 23);
background: linear-gradient(
180deg,
rgba(85, 202, 48, 1) 0%,
rgba(62, 183, 17, 1) 100%
);
}
.badge-status.pending {
background: rgb(247, 132, 71);
background: linear-gradient(
180deg,
rgba(247, 132, 71, 1) 0%,
rgba(228, 113, 49, 1) 100%
);
}
.badge-status.error,
.badge-status.failed {
background: rgb(221, 103, 81);
background: linear-gradient(
180deg,
rgba(221, 103, 81, 1) 0%,
rgba(201, 84, 61, 1) 100%
);
}
/* Thanks to
https://vineethtrv.github.io/loader/
and
https://www.w3schools.com/howto/howto_css_loader.asp
for inspiration
*/
.loader {
position: relative;
padding-left: 20px; /* spinner size * 2 */
}
.loader::before {
content: "";
display: inline-block;
position: absolute;
left: 0;
top: 0;
margin: 0px 6px 0px 2px;
border: 1px solid transparent;
border-radius: 50%;
border-top: 2px solid #fff;
width: 10px;
height: 10px;
animation: spin 1s ease-out infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}

Usage

function App() {
return (
<div className="App">
<BuildBadge
status="loading"
summary="loading..."
page_url="https://serpapi.com/search-api"
/>
<BuildBadge
status="error"
summary="125 examples, 3 failures"
page_url="https://serpapi.com/organic-results"
/>
<BuildBadge
status="success"
summary="50 examples, 0 failures"
page_url="https://serpapi.com/google-scholar-api"
/>
<BuildBadge
status="pending"
summary="87 examples, 2 pending"
page_url="https://serpapi.com/images-results"
/>
</div>
);
}

Thanks to Shields.io, Vineeth TR and W3Schools for inspiration.

--

--