Job Board — Application Status Pills
A clean, scannable application-status system for a job board or ATS — semantic pills for applied, screening, interview, offer, hired, and rejected, paired with a live horizontal stepper that animates as you transition between stages. Includes a featured tracker with advance, back, reject, and reset controls, plus a filterable pipeline list of fictional applications with company logos, remote and salary chips, save toggles, and a toast helper. Built with vanilla HTML, CSS, and JavaScript.
MCP
Code
:root {
--brand: #2563eb;
--brand-d: #1d4ed8;
--brand-50: #eaf1ff;
--ink: #0f172a;
--ink-2: #475569;
--muted: #64748b;
--bg: #f6f8fb;
--surface: #ffffff;
--line: rgba(15, 23, 42, 0.1);
--line-2: rgba(15, 23, 42, 0.18);
--ok: #16a34a;
--warn: #d97706;
--danger: #dc2626;
--new: #2563eb;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 20px;
--sh-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
--sh-md: 0 6px 20px rgba(15, 23, 42, 0.08);
--sh-lg: 0 18px 48px rgba(15, 23, 42, 0.12);
/* status tokens: text / bg / dot */
--applied: #2563eb; --applied-bg: #eaf1ff;
--screening: #7c3aed; --screening-bg: #f1ebff;
--interview: #d97706; --interview-bg: #fff3e0;
--offer: #0891b2; --offer-bg: #e2f6fb;
--hired: #16a34a; --hired-bg: #e6f7ec;
--rejected: #dc2626; --rejected-bg: #fdeaea;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, sans-serif;
font-size: 15px;
line-height: 1.5;
color: var(--ink);
background:
radial-gradient(1100px 520px at 88% -10%, #eef3ff 0%, transparent 60%),
var(--bg);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.wrap {
max-width: 980px;
margin: 0 auto;
padding: 40px 24px 72px;
}
h1, h2 { margin: 0; letter-spacing: -0.02em; }
/* ---------- header ---------- */
.page-head {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 28px;
margin-bottom: 28px;
}
.eyebrow {
margin: 0 0 6px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--brand);
}
.page-head h1 { font-size: 30px; font-weight: 800; }
.lede {
margin: 10px 0 0;
max-width: 46ch;
color: var(--ink-2);
}
.legend {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: flex-end;
max-width: 280px;
}
/* ---------- pills ---------- */
.pill {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 5px 11px 5px 9px;
border-radius: 999px;
font-size: 12.5px;
font-weight: 600;
white-space: nowrap;
border: 1px solid transparent;
background: #f1f5f9;
color: var(--ink-2);
line-height: 1;
}
.pill .dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 18%, transparent);
}
.pill.big { padding: 8px 15px 8px 12px; font-size: 14px; }
.pill-applied, [data-pill="applied"] { color: var(--applied); background: var(--applied-bg); border-color: color-mix(in srgb, var(--applied) 22%, transparent); }
.pill-screening, [data-pill="screening"] { color: var(--screening); background: var(--screening-bg); border-color: color-mix(in srgb, var(--screening) 22%, transparent); }
.pill-interview, [data-pill="interview"] { color: var(--interview); background: var(--interview-bg); border-color: color-mix(in srgb, var(--interview) 22%, transparent); }
.pill-offer, [data-pill="offer"] { color: var(--offer); background: var(--offer-bg); border-color: color-mix(in srgb, var(--offer) 22%, transparent); }
.pill-hired, [data-pill="hired"] { color: var(--hired); background: var(--hired-bg); border-color: color-mix(in srgb, var(--hired) 22%, transparent); }
.pill-rejected, [data-pill="rejected"] { color: var(--rejected); background: var(--rejected-bg); border-color: color-mix(in srgb, var(--rejected) 22%, transparent); }
/* ---------- featured card ---------- */
.featured {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-lg);
box-shadow: var(--sh-md);
padding: 24px 24px 22px;
margin-bottom: 32px;
}
.featured-top {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
margin-bottom: 30px;
}
.company { display: flex; align-items: center; gap: 14px; }
.logo {
display: grid;
place-items: center;
width: 46px;
height: 46px;
border-radius: var(--r-sm);
font-weight: 800;
font-size: 15px;
color: #fff;
background: linear-gradient(135deg, var(--brand), var(--brand-d));
box-shadow: var(--sh-sm);
flex: none;
}
.company-meta h2 { font-size: 18px; font-weight: 700; }
.company-meta p { margin: 3px 0 0; font-size: 13px; color: var(--muted); }
/* ---------- stepper ---------- */
.stepper {
list-style: none;
display: flex;
margin: 0 0 26px;
padding: 0 4px;
counter-reset: none;
}
.step {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 9px;
text-align: center;
}
/* connector line */
.step::before {
content: "";
position: absolute;
top: 16px;
left: -50%;
width: 100%;
height: 3px;
background: var(--line);
border-radius: 3px;
z-index: 0;
transition: background 0.45s ease;
}
.step:first-child::before { display: none; }
.node {
position: relative;
z-index: 1;
display: grid;
place-items: center;
width: 34px;
height: 34px;
border-radius: 50%;
background: var(--surface);
border: 2px solid var(--line-2);
color: var(--muted);
font-weight: 700;
font-size: 13px;
transition: transform 0.3s ease, background 0.3s ease, border-color 0.3s ease, color 0.3s ease;
}
.node .check { display: none; }
.node .num { display: block; }
.step-label {
font-size: 12px;
font-weight: 600;
color: var(--muted);
transition: color 0.3s ease;
}
/* states applied by JS */
.step.done::before { background: var(--ok); }
.step.done .node {
background: var(--ok);
border-color: var(--ok);
color: #fff;
}
.step.done .node .check { display: block; }
.step.done .node .num { display: none; }
.step.done .step-label { color: var(--ink-2); }
.step.current::before { background: var(--ok); }
.step.current .node {
background: var(--brand);
border-color: var(--brand);
color: #fff;
transform: scale(1.12);
box-shadow: 0 0 0 6px var(--brand-50);
}
.step.current .step-label { color: var(--ink); font-weight: 700; }
/* rejected flavour */
.stepper.rejected .step.current .node {
background: var(--danger);
border-color: var(--danger);
box-shadow: 0 0 0 6px color-mix(in srgb, var(--danger) 16%, transparent);
}
.stepper.rejected .step.current::before,
.stepper.rejected .step.done::before { background: color-mix(in srgb, var(--danger) 55%, #cbd5e1); }
.node.bump { animation: bump 0.4s ease; }
@keyframes bump {
0% { transform: scale(0.85); }
55% { transform: scale(1.25); }
100% { transform: scale(1.12); }
}
/* ---------- controls ---------- */
.controls { display: flex; flex-wrap: wrap; gap: 10px; }
.btn {
appearance: none;
border: 1px solid var(--line-2);
background: var(--surface);
color: var(--ink);
font: inherit;
font-weight: 600;
font-size: 13.5px;
padding: 9px 15px;
border-radius: var(--r-sm);
cursor: pointer;
transition: background 0.15s ease, border-color 0.15s ease, transform 0.06s ease, box-shadow 0.15s ease;
}
.btn:hover { border-color: var(--line-2); background: #f8fafc; }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.btn.primary {
background: var(--brand);
border-color: var(--brand);
color: #fff;
box-shadow: var(--sh-sm);
}
.btn.primary:hover { background: var(--brand-d); border-color: var(--brand-d); }
.btn.primary:disabled,
.btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
.btn.ghost { background: transparent; }
.btn.danger-ghost { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.btn.danger-ghost:hover { background: var(--rejected-bg); }
/* ---------- list ---------- */
.list-head {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
margin-bottom: 14px;
flex-wrap: wrap;
}
.list-head h2 { font-size: 18px; font-weight: 700; }
.filters { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
appearance: none;
border: 1px solid var(--line);
background: var(--surface);
color: var(--ink-2);
font: inherit;
font-weight: 600;
font-size: 13px;
padding: 6px 12px;
border-radius: 999px;
cursor: pointer;
transition: all 0.15s ease;
display: inline-flex;
align-items: center;
gap: 6px;
}
.chip:hover { border-color: var(--line-2); }
.chip:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.chip.is-active { background: var(--ink); border-color: var(--ink); color: #fff; }
.chip .count {
font-size: 11px;
font-weight: 700;
background: var(--brand-50);
color: var(--brand);
padding: 1px 7px;
border-radius: 999px;
}
.chip.is-active .count { background: rgba(255,255,255,0.18); color: #fff; }
.rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.row {
display: grid;
grid-template-columns: 42px 1fr auto auto;
align-items: center;
gap: 14px;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-md);
padding: 13px 16px;
box-shadow: var(--sh-sm);
transition: box-shadow 0.18s ease, transform 0.18s ease, border-color 0.18s ease, opacity 0.25s ease;
}
.row:hover { box-shadow: var(--sh-md); border-color: var(--line-2); transform: translateY(-1px); }
.row[hidden] { display: none; }
.row.is-fading { opacity: 0; transform: translateY(-4px); }
.row .r-logo {
width: 42px; height: 42px;
border-radius: var(--r-sm);
display: grid; place-items: center;
font-weight: 800; font-size: 13px; color: #fff;
}
.row .r-main { min-width: 0; }
.row .r-role { font-weight: 700; font-size: 14.5px; color: var(--ink); }
.row .r-sub {
margin-top: 2px;
font-size: 12.5px;
color: var(--muted);
display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center;
}
.r-chip {
display: inline-flex; align-items: center; gap: 4px;
font-size: 11.5px; font-weight: 600;
color: var(--ink-2);
background: #f1f5f9;
padding: 2px 8px;
border-radius: 999px;
}
.r-chip.remote { color: var(--brand); background: var(--brand-50); }
.row .r-meta { font-size: 12px; color: var(--muted); white-space: nowrap; }
.save {
appearance: none;
border: 1px solid var(--line);
background: var(--surface);
width: 34px; height: 34px;
border-radius: var(--r-sm);
cursor: pointer;
display: grid; place-items: center;
color: var(--muted);
transition: all 0.15s ease;
}
.save:hover { border-color: var(--line-2); color: var(--ink-2); background: #f8fafc; }
.save:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.save.is-saved { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); background: #fffaf0; }
.save svg { width: 17px; height: 17px; }
/* ---------- toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 26px;
transform: translate(-50%, 18px);
background: var(--ink);
color: #fff;
font-size: 13.5px;
font-weight: 600;
padding: 11px 18px;
border-radius: 999px;
box-shadow: var(--sh-lg);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s ease, transform 0.25s ease;
z-index: 50;
max-width: calc(100vw - 32px);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation: none !important; transition: none !important; }
}
/* ---------- responsive ---------- */
@media (max-width: 720px) {
.page-head { flex-direction: column; }
.legend { justify-content: flex-start; max-width: none; }
}
@media (max-width: 520px) {
.wrap { padding: 28px 16px 64px; }
.page-head h1 { font-size: 25px; }
.step-label { font-size: 10.5px; }
.node { width: 30px; height: 30px; }
.step::before { top: 14px; }
.controls .btn { flex: 1 1 calc(50% - 5px); justify-content: center; }
.row {
grid-template-columns: 38px 1fr auto;
grid-template-areas: "logo main save";
column-gap: 11px;
}
.row .r-logo { grid-area: logo; }
.row .r-main { grid-area: main; }
.row .save { grid-area: save; }
.row .r-pill-wrap { grid-column: 2 / -1; margin-top: 2px; }
.featured-top { flex-direction: column; align-items: flex-start; }
}(function () {
"use strict";
// Ordered active stages (rejected is a terminal off-track state)
var STAGES = ["applied", "screening", "interview", "offer", "hired"];
var LABELS = {
applied: "Applied",
screening: "Screening",
interview: "Interview",
offer: "Offer",
hired: "Hired",
rejected: "Rejected"
};
/* ---------- toast helper ---------- */
var toastEl = document.getElementById("toast");
var toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2200);
}
/* ---------- featured stepper ---------- */
var stepper = document.getElementById("stepper");
var steps = Array.prototype.slice.call(stepper.querySelectorAll(".step"));
var featPill = document.getElementById("feat-pill");
var featLabel = featPill.querySelector("[data-pill-label]");
var btnAdvance = document.getElementById("btn-advance");
var btnBack = document.getElementById("btn-back");
var btnReject = document.getElementById("btn-reject");
var btnReset = document.getElementById("btn-reset");
var state = { stage: "interview", rejected: false };
function renderStepper(animate) {
var idx = STAGES.indexOf(state.stage);
steps.forEach(function (step, i) {
step.classList.remove("done", "current");
if (state.rejected) {
if (i < idx) step.classList.add("done");
else if (i === idx) step.classList.add("current");
} else {
if (i < idx) step.classList.add("done");
else if (i === idx) step.classList.add("current");
}
});
stepper.classList.toggle("rejected", state.rejected);
// pill
var key = state.rejected ? "rejected" : state.stage;
featPill.setAttribute("data-pill", key);
featLabel.textContent = LABELS[key];
// bump animation on the active node
if (animate) {
var active = steps[idx] && steps[idx].querySelector(".node");
if (active) {
active.classList.remove("bump");
// force reflow so the animation can re-trigger
void active.offsetWidth;
active.classList.add("bump");
}
}
// button availability
btnAdvance.disabled = !state.rejected && state.stage === "hired";
btnBack.disabled = state.rejected || state.stage === "applied";
}
btnAdvance.addEventListener("click", function () {
if (state.rejected) {
// re-open a rejected application back onto the track
state.rejected = false;
renderStepper(true);
toast("Re-opened — back to " + LABELS[state.stage]);
return;
}
var idx = STAGES.indexOf(state.stage);
if (idx < STAGES.length - 1) {
state.stage = STAGES[idx + 1];
renderStepper(true);
toast(
state.stage === "hired"
? "Hired! Offer accepted 🎉"
: "Moved to " + LABELS[state.stage]
);
}
});
btnBack.addEventListener("click", function () {
var idx = STAGES.indexOf(state.stage);
if (idx > 0) {
state.stage = STAGES[idx - 1];
renderStepper(true);
toast("Moved back to " + LABELS[state.stage]);
}
});
btnReject.addEventListener("click", function () {
if (state.rejected) {
toast("Already marked rejected");
return;
}
state.rejected = true;
renderStepper(true);
toast("Application marked rejected");
});
btnReset.addEventListener("click", function () {
state = { stage: "applied", rejected: false };
renderStepper(true);
toast("Reset to Applied");
});
renderStepper(false);
/* ---------- application list ---------- */
var APPS = [
{ role: "Product Designer", co: "Lumen Labs", logo: "LL", color: "#7c3aed", loc: "Berlin", remote: true, pay: "€72k", status: "screening", saved: false, when: "2d ago" },
{ role: "Backend Engineer (Go)", co: "Harborstack", logo: "HS", color: "#0891b2", loc: "Remote (EU)", remote: true, pay: "€95k", status: "interview", saved: true, when: "4h ago" },
{ role: "Data Analyst", co: "Brightpath", logo: "BP", color: "#16a34a", loc: "Madrid", remote: false, pay: "€48k", status: "applied", saved: false, when: "1d ago" },
{ role: "Engineering Manager", co: "Novabyte", logo: "NV", color: "#2563eb", loc: "Lisbon", remote: true, pay: "€118k", status: "offer", saved: true, when: "6h ago" },
{ role: "UX Researcher", co: "Cedarwave", logo: "CW", color: "#d97706", loc: "Amsterdam", remote: false, pay: "€61k", status: "hired", saved: false, when: "Yesterday" },
{ role: "DevOps Engineer", co: "Quartz IO", logo: "QZ", color: "#dc2626", loc: "Remote", remote: true, pay: "€88k", status: "rejected", saved: false, when: "3d ago" }
];
var rows = document.getElementById("rows");
var currentFilter = "all";
var ACTIVE = ["applied", "screening", "interview"];
function matchesFilter(status, filter) {
if (filter === "all") return true;
if (filter === "active") return ACTIVE.indexOf(status) !== -1;
if (filter === "offer") return status === "offer" || status === "hired";
if (filter === "rejected") return status === "rejected";
return true;
}
var BOOKMARK =
'<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">' +
'<path d="M6 4.5C6 3.67 6.67 3 7.5 3h9C17.33 3 18 3.67 18 4.5V21l-6-3.6L6 21V4.5Z" ' +
'stroke="currentColor" stroke-width="1.7" stroke-linejoin="round" ' +
'class="bm-fill"/></svg>';
function buildRow(app, i) {
var li = document.createElement("li");
li.className = "row";
li.dataset.status = app.status;
li.dataset.idx = i;
if (!matchesFilter(app.status, currentFilter)) li.hidden = true;
var remoteChip = app.remote
? '<span class="r-chip remote">Remote</span>'
: '<span class="r-chip">On-site</span>';
li.innerHTML =
'<span class="r-logo" style="background:' + app.color + '">' + app.logo + "</span>" +
'<div class="r-main">' +
'<div class="r-role">' + app.role + "</div>" +
'<div class="r-sub">' +
"<span>" + app.co + "</span>" +
'<span class="r-chip">' + app.loc + "</span>" +
remoteChip +
'<span class="r-chip">' + app.pay + "</span>" +
'<span class="r-pill-wrap"><span class="pill" data-pill="' + app.status + '">' +
'<span class="dot"></span>' + LABELS[app.status] + "</span></span>" +
"</div>" +
"</div>" +
'<span class="r-meta">' + app.when + "</span>" +
'<button type="button" class="save' + (app.saved ? " is-saved" : "") +
'" aria-pressed="' + app.saved + '" aria-label="Save ' + app.role + '">' +
BOOKMARK + "</button>";
var saveBtn = li.querySelector(".save");
saveBtn.addEventListener("click", function () {
app.saved = !app.saved;
saveBtn.classList.toggle("is-saved", app.saved);
saveBtn.setAttribute("aria-pressed", String(app.saved));
saveBtn.querySelector(".bm-fill").setAttribute("fill", app.saved ? "currentColor" : "none");
toast(app.saved ? "Saved " + app.role : "Removed from saved");
});
if (app.saved) li.querySelector(".bm-fill").setAttribute("fill", "currentColor");
return li;
}
function renderList() {
rows.innerHTML = "";
APPS.forEach(function (app, i) {
rows.appendChild(buildRow(app, i));
});
}
function applyFilter(filter) {
currentFilter = filter;
Array.prototype.forEach.call(rows.children, function (li) {
li.hidden = !matchesFilter(li.dataset.status, filter);
});
}
// filter chips
var chips = Array.prototype.slice.call(document.querySelectorAll(".chip"));
chips.forEach(function (chip) {
chip.addEventListener("click", function () {
chips.forEach(function (c) {
c.classList.remove("is-active");
c.setAttribute("aria-selected", "false");
});
chip.classList.add("is-active");
chip.setAttribute("aria-selected", "true");
applyFilter(chip.dataset.filter);
});
});
// total count badge
var countAll = document.querySelector("[data-count-all]");
if (countAll) countAll.textContent = String(APPS.length);
renderList();
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Job Board — Application Status Pills</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="wrap">
<header class="page-head">
<div>
<p class="eyebrow">Applications</p>
<h1>Status pills & stepper</h1>
<p class="lede">Track every application from first click to signed offer. Semantic pills, a live stepper, and one-tap transitions.</p>
</div>
<div class="legend" aria-hidden="true">
<span class="pill pill-applied"><span class="dot"></span>Applied</span>
<span class="pill pill-screening"><span class="dot"></span>Screening</span>
<span class="pill pill-interview"><span class="dot"></span>Interview</span>
<span class="pill pill-offer"><span class="dot"></span>Offer</span>
<span class="pill pill-hired"><span class="dot"></span>Hired</span>
<span class="pill pill-rejected"><span class="dot"></span>Rejected</span>
</div>
</header>
<!-- Featured tracker -->
<section class="featured" aria-label="Selected application">
<div class="featured-top">
<div class="company">
<span class="logo" data-logo>NV</span>
<div class="company-meta">
<h2 id="feat-role">Senior Frontend Engineer</h2>
<p id="feat-co">Novabyte · Remote · €92k–€115k</p>
</div>
</div>
<span class="pill big" id="feat-pill" data-pill="interview"><span class="dot"></span><span data-pill-label>Interview</span></span>
</div>
<ol class="stepper" id="stepper" aria-label="Application progress">
<li class="step" data-step="applied"><span class="node"><span class="check" aria-hidden="true">✓</span><span class="num">1</span></span><span class="step-label">Applied</span></li>
<li class="step" data-step="screening"><span class="node"><span class="check" aria-hidden="true">✓</span><span class="num">2</span></span><span class="step-label">Screening</span></li>
<li class="step" data-step="interview"><span class="node"><span class="check" aria-hidden="true">✓</span><span class="num">3</span></span><span class="step-label">Interview</span></li>
<li class="step" data-step="offer"><span class="node"><span class="check" aria-hidden="true">✓</span><span class="num">4</span></span><span class="step-label">Offer</span></li>
<li class="step" data-step="hired"><span class="node"><span class="check" aria-hidden="true">✓</span><span class="num">5</span></span><span class="step-label">Hired</span></li>
</ol>
<div class="controls" role="group" aria-label="Update status">
<button type="button" class="btn ghost" id="btn-back" aria-label="Move back one stage">← Back</button>
<button type="button" class="btn primary" id="btn-advance">Advance stage →</button>
<button type="button" class="btn danger-ghost" id="btn-reject">Mark rejected</button>
<button type="button" class="btn ghost" id="btn-reset">Reset</button>
</div>
</section>
<!-- Application list -->
<section class="list" aria-label="All applications">
<div class="list-head">
<h2>Your pipeline</h2>
<div class="filters" role="tablist" aria-label="Filter by status">
<button class="chip is-active" role="tab" aria-selected="true" data-filter="all">All <span class="count" data-count-all>0</span></button>
<button class="chip" role="tab" aria-selected="false" data-filter="active">Active</button>
<button class="chip" role="tab" aria-selected="false" data-filter="offer">Offers</button>
<button class="chip" role="tab" aria-selected="false" data-filter="rejected">Closed</button>
</div>
</div>
<ul class="rows" id="rows"></ul>
</section>
</main>
<div class="toast" id="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Application Status Pills
A trustworthy, scannable status system for tracking job applications. Six semantic pills — applied, screening, interview, offer, hired, and rejected — each get their own color token, soft tinted background, and a glowing status dot, so the stage of any application reads at a glance. The same pill styling drives both the legend in the header and the inline badges on every pipeline row.
The featured tracker pairs the active pill with a horizontal stepper. Completed stages fill green with a check, the current stage scales up in brand blue with a focus ring, and the connector line animates as you move. Use the Advance, Back, Reject, and Reset buttons to walk an application through its lifecycle — marking it rejected recolors the stepper, while advancing past it re-opens the application back onto the track. A bumping micro-animation and a toast confirm every transition.
Below the tracker sits a filterable pipeline of fictional applications. Each row carries a company logo, location, remote or on-site chip, salary, a status pill, and a bookmark toggle that fills in on save. Filter chips switch between all, active, offers, and closed roles, and a count badge keeps a running total. Everything is keyboard-usable, responsive down to ~360px, and written in dependency-free vanilla JavaScript.
Illustrative UI only — fictional jobs & companies, not a real hiring platform.