Ilya Zub

Build badge in React without SVG and no dependencies

Ilya
Ilya

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.

An example of build badges on SerpApi documentation pages

Badge component 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>
  );
}

Badge component itself

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);
  }
}

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


More Stories

One year of working from home with kid and wife

What I do to enjoy my life when working from home: play more, work less (mostly).

Ilya
Ilya

SerpApi will sponsor SEO Day conference

Made a Kanban board in Notion for myself. Next action — prepare a SerpApi description for a Facebook post in SEO Day channel. Due to September 10th.

Ilya
Ilya