Open demo

CSS code

HTML
<div><span class="lbl">Solid pills · invoice status</span>
<ul class="bdg-row">
  <li><span class="bdg ok"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg>Paid</span></li>
  <li><span class="bdg warn"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/><path d="M8 5v3.2l2 1.3"/></svg>Pending</span></li>
  <li><span class="bdg bad"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/><path d="M8 5v3.5M8 11h.01"/></svg>Overdue</span></li>
  <li><span class="bdg info"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8a5 5 0 1 0 1.5-3.6M3 3v2.6h2.6"/></svg>Refunded</span></li>
  <li><span class="bdg mute"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10.5 3.5l2 2L6 12H4v-2z"/></svg>Draft</span></li>
</ul></div>

<div><span class="lbl">Dot badges · service health</span>
<ul class="bdg-row">
  <li><span class="bdg dot ok">Operational</span></li>
  <li><span class="bdg dot warn">Degraded</span></li>
  <li><span class="bdg dot bad">Major outage</span></li>
  <li><span class="bdg dot info">Maintenance</span></li>
  <li><span class="bdg dot live">Live</span></li>
</ul></div>

<div><span class="lbl">Soft badges · order status</span>
<ul class="bdg-row">
  <li><span class="bdg soft ok">Delivered</span></li>
  <li><span class="bdg soft warn">Awaiting stock</span></li>
  <li><span class="bdg soft bad">Cancelled</span></li>
  <li><span class="bdg soft info">Shipped</span></li>
  <li><span class="bdg soft">Archived</span></li>
</ul></div>

<div><span class="lbl">Outline badges · job details</span>
<ul class="bdg-row">
  <li><span class="bdg line indigo">Remote</span></li>
  <li><span class="bdg line teal">Full-time</span></li>
  <li><span class="bdg line amber">Contract</span></li>
  <li><span class="bdg line pink">Senior</span></li>
  <li><span class="bdg line">Visa sponsored</span></li>
</ul></div>

<div><span class="lbl">Counts on icon and text buttons</span>
<div class="bdg-row ib-row">
  <button class="ib" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9a6 6 0 1 1 12 0c0 6 2.5 8 2.5 8h-17S6 15 6 9"/><path d="M10.3 20.5a2 2 0 0 0 3.4 0"/></svg><span class="sr-only">Notifications,</span><span class="cnt">3<span class="sr-only"> unread</span></span></button>
  <button class="ib" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="M3.5 7.5l8.5 6 8.5-6"/></svg><span class="sr-only">Messages,</span><span class="cnt">12<span class="sr-only"> unread</span></span></button>
  <button class="ib" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="9.5" cy="19.5" r="1.4"/><circle cx="17.5" cy="19.5" r="1.4"/><path d="M2.5 3.5h3l2.4 11a2 2 0 0 0 2 1.5h7.4a2 2 0 0 0 2-1.6L21 7.5H6.3"/></svg><span class="sr-only">Basket,</span><span class="cnt dk">2<span class="sr-only"> items</span></span></button>
  <button class="ib" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3.5v11m0 0l-4-4m4 4l4-4M4.5 16.5v2a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-2"/></svg><span class="sr-only">Updates,</span><span class="cnt">99+<span class="sr-only"> waiting</span></span></button>
  <button class="ib" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.5 12a8.5 8.5 0 0 1-12.3 7.6L3.5 21l1.4-4.5A8.5 8.5 0 1 1 20.5 12z"/></svg><span class="sr-only">Comments, new replies</span><span class="cnt pip" aria-hidden="true"></span></button>
  <button class="tb" type="button">Inbox <span class="n">24<span class="sr-only"> new</span></span></button>
</div></div>
CSS
/* Status and count badges. Every badge carries a word, so colour is never the only signal.
   Counts on icon buttons add visually hidden text ("3 unread") so the button name reads in full. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.bdg-row{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:0;padding:0;list-style:none}
.ib-row{gap:22px}
.bdg{--bdg-bg:#475569;--bdg-fg:#fff;--bdg-line:transparent;
  display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border:1px solid var(--bdg-line);border-radius:999px;
  background:var(--bdg-bg);color:var(--bdg-fg);font-size:.75rem;font-weight:600;line-height:1.25;letter-spacing:.01em;white-space:nowrap}
.bdg svg{width:12px;height:12px;flex:none;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
/* solid */
.bdg.ok{--bdg-bg:#15803d}.bdg.warn{--bdg-bg:#b45309}.bdg.bad{--bdg-bg:#b91c1c}.bdg.info{--bdg-bg:#1d4ed8}.bdg.mute{--bdg-bg:#475569}
/* dot: neutral pill, coloured dot, the word says the state */
.bdg.dot{--bdg-bg:#fff;--bdg-fg:#1e293b;--bdg-line:#cbd5e1;--dot:#64748b}
.bdg.dot::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--dot);flex:none}
.bdg.dot.ok{--dot:#16a34a}.bdg.dot.warn{--dot:#d97706}.bdg.dot.bad{--dot:#dc2626}.bdg.dot.info{--dot:#2563eb}
.bdg.dot.live{--dot:#dc2626;position:relative}
.bdg.dot.live::after{content:"";position:absolute;left:10px;width:8px;height:8px;border-radius:50%;background:var(--dot);animation:bdg-ping 1.6s ease-out infinite}
@keyframes bdg-ping{from{transform:scale(1);opacity:.6}to{transform:scale(2.6);opacity:0}}
/* soft: tinted ground, dark text of the same hue */
.bdg.soft{--bdg-bg:#f1f5f9;--bdg-fg:#334155}
.bdg.soft.ok{--bdg-bg:#dcfce7;--bdg-fg:#166534}.bdg.soft.warn{--bdg-bg:#fef3c7;--bdg-fg:#92400e}
.bdg.soft.bad{--bdg-bg:#fee2e2;--bdg-fg:#991b1b}.bdg.soft.info{--bdg-bg:#dbeafe;--bdg-fg:#1e40af}
/* outline */
.bdg.line{--bdg-bg:transparent;--bdg-fg:#334155;--bdg-line:currentColor;border-width:1.5px}
.bdg.line.indigo{--bdg-fg:#4338ca}.bdg.line.teal{--bdg-fg:#0f766e}.bdg.line.amber{--bdg-fg:#a14d07}.bdg.line.pink{--bdg-fg:#be185d}
/* count on an icon button */
.ib{position:relative;display:inline-grid;place-items:center;width:44px;height:44px;border:1px solid #cbd5e1;border-radius:12px;
  background:#fff;color:#1e293b;cursor:pointer;transition:background-color .15s,border-color .15s}
.ib:hover{background:#f1f5f9;border-color:#94a3b8}
.ib:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
.ib svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.cnt{position:absolute;top:0;left:100%;transform:translate(-50%,-50%);min-width:20px;height:20px;padding:0 6px;border:2px solid #f8fafc;
  border-radius:999px;background:#dc2626;color:#fff;font-size:.68rem;font-weight:700;line-height:16px;text-align:center}
.cnt.dk{background:#0f172a}
.cnt.pip{min-width:0;width:12px;height:12px;padding:0;top:4px;left:auto;right:4px;transform:none}
/* count inside a text button */
.tb{display:inline-flex;align-items:center;gap:8px;padding:9px 14px;border:1px solid #cbd5e1;border-radius:10px;background:#fff;
  color:#1e293b;font:inherit;font-size:.9rem;font-weight:600;cursor:pointer;transition:background-color .15s}
.tb:hover{background:#f1f5f9}
.tb:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
.tb .n{padding:2px 8px;border-radius:999px;background:#e0e7ff;color:#3730a3;font-size:.72rem;font-weight:700;line-height:1.3}
@media (prefers-reduced-motion:reduce){.ib,.tb{transition:none}.bdg.dot.live::after{animation:none;opacity:0}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Solid pills · invoice status</span>
<ul class="list-unstyled d-flex flex-wrap align-items-center sb-row m-0">
  <li><span class="badge rounded-pill sb ok"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg>Paid</span></li>
  <li><span class="badge rounded-pill sb warn"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/><path d="M8 5v3.2l2 1.3"/></svg>Pending</span></li>
  <li><span class="badge rounded-pill sb bad"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/><path d="M8 5v3.5M8 11h.01"/></svg>Overdue</span></li>
  <li><span class="badge rounded-pill sb info"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8a5 5 0 1 0 1.5-3.6M3 3v2.6h2.6"/></svg>Refunded</span></li>
  <li><span class="badge rounded-pill sb mute"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M10.5 3.5l2 2L6 12H4v-2z"/></svg>Draft</span></li>
</ul></div>

<div><span class="lbl">Dot badges · service health</span>
<ul class="list-unstyled d-flex flex-wrap align-items-center sb-row m-0">
  <li><span class="badge rounded-pill sb dot ok">Operational</span></li>
  <li><span class="badge rounded-pill sb dot warn">Degraded</span></li>
  <li><span class="badge rounded-pill sb dot bad">Major outage</span></li>
  <li><span class="badge rounded-pill sb dot info">Maintenance</span></li>
  <li><span class="badge rounded-pill sb dot live">Live</span></li>
</ul></div>

<div><span class="lbl">Soft badges · order status</span>
<ul class="list-unstyled d-flex flex-wrap align-items-center sb-row m-0">
  <li><span class="badge rounded-pill sb soft ok">Delivered</span></li>
  <li><span class="badge rounded-pill sb soft warn">Awaiting stock</span></li>
  <li><span class="badge rounded-pill sb soft bad">Cancelled</span></li>
  <li><span class="badge rounded-pill sb soft info">Shipped</span></li>
  <li><span class="badge rounded-pill sb soft">Archived</span></li>
</ul></div>

<div><span class="lbl">Outline badges · job details</span>
<ul class="list-unstyled d-flex flex-wrap align-items-center sb-row m-0">
  <li><span class="badge rounded-pill sb line indigo">Remote</span></li>
  <li><span class="badge rounded-pill sb line teal">Full-time</span></li>
  <li><span class="badge rounded-pill sb line amber">Contract</span></li>
  <li><span class="badge rounded-pill sb line pink">Senior</span></li>
  <li><span class="badge rounded-pill sb line">Visa sponsored</span></li>
</ul></div>

<div><span class="lbl">Counts on icon and text buttons</span>
<div class="d-flex flex-wrap align-items-center ib-row">
  <button class="btn ib position-relative" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9a6 6 0 1 1 12 0c0 6 2.5 8 2.5 8h-17S6 15 6 9"/><path d="M10.3 20.5a2 2 0 0 0 3.4 0"/></svg><span class="visually-hidden">Notifications,</span><span class="position-absolute top-0 start-100 translate-middle badge rounded-pill cnt">3<span class="visually-hidden"> unread</span></span></button>
  <button class="btn ib position-relative" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="M3.5 7.5l8.5 6 8.5-6"/></svg><span class="visually-hidden">Messages,</span><span class="position-absolute top-0 start-100 translate-middle badge rounded-pill cnt">12<span class="visually-hidden"> unread</span></span></button>
  <button class="btn ib position-relative" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="9.5" cy="19.5" r="1.4"/><circle cx="17.5" cy="19.5" r="1.4"/><path d="M2.5 3.5h3l2.4 11a2 2 0 0 0 2 1.5h7.4a2 2 0 0 0 2-1.6L21 7.5H6.3"/></svg><span class="visually-hidden">Basket,</span><span class="position-absolute top-0 start-100 translate-middle badge rounded-pill cnt dk">2<span class="visually-hidden"> items</span></span></button>
  <button class="btn ib position-relative" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3.5v11m0 0l-4-4m4 4l4-4M4.5 16.5v2a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-2"/></svg><span class="visually-hidden">Updates,</span><span class="position-absolute top-0 start-100 translate-middle badge rounded-pill cnt">99+<span class="visually-hidden"> waiting</span></span></button>
  <button class="btn ib position-relative" type="button"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20.5 12a8.5 8.5 0 0 1-12.3 7.6L3.5 21l1.4-4.5A8.5 8.5 0 1 1 20.5 12z"/></svg><span class="visually-hidden">Comments, new replies</span><span class="position-absolute badge rounded-pill cnt pip" aria-hidden="true"></span></button>
  <button class="btn tb" type="button">Inbox <span class="badge rounded-pill">24<span class="visually-hidden"> new</span></span></button>
</div></div>
CSS
/* Status and count badges on Bootstrap's .badge, .rounded-pill and .btn, restyled through --bs-badge-* and --bs-btn-* variables.
   Every badge carries a word; counts on icon buttons add .visually-hidden text ("3 unread"). */
.sb{--bs-badge-padding-x:10px;--bs-badge-padding-y:4px;--bs-badge-font-size:.75rem;--bs-badge-font-weight:600;--bs-badge-color:#fff;
  display:inline-flex;align-items:center;gap:6px;line-height:1.25;letter-spacing:.01em;border:1px solid transparent;background:#475569}
.sb svg{width:12px;height:12px;flex:none;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.sb.ok{background:#15803d}.sb.warn{background:#b45309}.sb.bad{background:#b91c1c}.sb.info{background:#1d4ed8}.sb.mute{background:#475569}
.sb.dot{--dot:#64748b;--bs-badge-color:#1e293b;background:#fff;border-color:#cbd5e1}
.sb.dot::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--dot);flex:none}
.sb.dot.ok{--dot:#16a34a}.sb.dot.warn{--dot:#d97706}.sb.dot.bad{--dot:#dc2626}.sb.dot.info{--dot:#2563eb}
.sb.dot.live{--dot:#dc2626;position:relative}
.sb.dot.live::after{content:"";position:absolute;left:10px;width:8px;height:8px;border-radius:50%;background:var(--dot);animation:sb-ping 1.6s ease-out infinite}
@keyframes sb-ping{from{transform:scale(1);opacity:.6}to{transform:scale(2.6);opacity:0}}
.sb.soft{--bs-badge-color:#334155;background:#f1f5f9}
.sb.soft.ok{--bs-badge-color:#166534;background:#dcfce7}.sb.soft.warn{--bs-badge-color:#92400e;background:#fef3c7}
.sb.soft.bad{--bs-badge-color:#991b1b;background:#fee2e2}.sb.soft.info{--bs-badge-color:#1e40af;background:#dbeafe}
.sb.line{--bs-badge-color:#334155;background:transparent;border:1.5px solid currentColor}
.sb.line.indigo{--bs-badge-color:#4338ca}.sb.line.teal{--bs-badge-color:#0f766e}.sb.line.amber{--bs-badge-color:#a14d07}.sb.line.pink{--bs-badge-color:#be185d}
.sb-row{gap:10px}
.ib-row{gap:22px}
.ib{--bs-btn-padding-x:0;--bs-btn-padding-y:0;--bs-btn-color:#1e293b;--bs-btn-bg:#fff;--bs-btn-border-color:#cbd5e1;--bs-btn-border-radius:12px;
  --bs-btn-hover-color:#1e293b;--bs-btn-hover-bg:#f1f5f9;--bs-btn-hover-border-color:#94a3b8;--bs-btn-active-color:#1e293b;--bs-btn-active-bg:#e2e8f0;--bs-btn-active-border-color:#94a3b8;
  display:inline-grid;place-items:center;width:44px;height:44px;transition:background-color .15s,border-color .15s}
.ib:focus-visible,.tb:focus-visible{outline:2px solid #4f46e5;outline-offset:2px;box-shadow:none}
.ib svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.cnt{--bs-badge-padding-x:6px;--bs-badge-padding-y:0;--bs-badge-font-size:.68rem;--bs-badge-font-weight:700;min-width:20px;height:20px;line-height:16px;border:2px solid #f8fafc;background:#dc2626}
.cnt.dk{background:#0f172a}
.cnt.pip{display:block;min-width:0;width:12px;height:12px;padding:0;top:4px;right:4px}
.tb{--bs-btn-padding-x:14px;--bs-btn-padding-y:9px;--bs-btn-font-size:.9rem;--bs-btn-font-weight:600;--bs-btn-line-height:normal;--bs-btn-color:#1e293b;--bs-btn-bg:#fff;--bs-btn-border-color:#cbd5e1;--bs-btn-border-radius:10px;
  --bs-btn-hover-color:#1e293b;--bs-btn-hover-bg:#f1f5f9;--bs-btn-hover-border-color:#cbd5e1;--bs-btn-active-color:#1e293b;--bs-btn-active-bg:#e2e8f0;--bs-btn-active-border-color:#cbd5e1;
  display:inline-flex;align-items:center;gap:8px;transition:background-color .15s}
.tb .badge{--bs-badge-padding-x:8px;--bs-badge-padding-y:2px;--bs-badge-font-size:.72rem;--bs-badge-color:#3730a3;line-height:1.3;background:#e0e7ff}
@media (prefers-reduced-motion:reduce){.ib,.tb{transition:none}.sb.dot.live::after{animation:none;opacity:0}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#526072] uppercase">Solid pills · invoice status</span>
<ul class="flex flex-wrap items-center gap-2.5">
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-transparent bg-[#15803d] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-white"><svg class="size-3 flex-none" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg>Paid</span></li>
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-transparent bg-[#b45309] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-white"><svg class="size-3 flex-none" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/><path d="M8 5v3.2l2 1.3"/></svg>Pending</span></li>
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-transparent bg-[#b91c1c] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-white"><svg class="size-3 flex-none" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/><path d="M8 5v3.5M8 11h.01"/></svg>Overdue</span></li>
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-transparent bg-[#1d4ed8] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-white"><svg class="size-3 flex-none" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 8a5 5 0 1 0 1.5-3.6M3 3v2.6h2.6"/></svg>Refunded</span></li>
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-transparent bg-[#475569] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-white"><svg class="size-3 flex-none" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.5 3.5l2 2L6 12H4v-2z"/></svg>Draft</span></li>
</ul></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#526072] uppercase">Dot badges · service health</span>
<ul class="flex flex-wrap items-center gap-2.5">
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-[#cbd5e1] bg-white px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#1e293b] before:size-2 before:flex-none before:rounded-full before:bg-[#16a34a]">Operational</span></li>
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-[#cbd5e1] bg-white px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#1e293b] before:size-2 before:flex-none before:rounded-full before:bg-[#d97706]">Degraded</span></li>
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-[#cbd5e1] bg-white px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#1e293b] before:size-2 before:flex-none before:rounded-full before:bg-[#dc2626]">Major outage</span></li>
  <li><span class="inline-flex items-center gap-1.5 rounded-full border border-[#cbd5e1] bg-white px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#1e293b] before:size-2 before:flex-none before:rounded-full before:bg-[#2563eb]">Maintenance</span></li>
  <li><span class="relative inline-flex items-center gap-1.5 rounded-full border border-[#cbd5e1] bg-white px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#1e293b] before:size-2 before:flex-none before:rounded-full before:bg-[#dc2626] after:absolute after:left-2.5 after:size-2 after:rounded-full after:bg-[#dc2626] after:animate-bdg-ping motion-reduce:after:animate-none motion-reduce:after:opacity-0">Live</span></li>
</ul></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#526072] uppercase">Soft badges · order status</span>
<ul class="flex flex-wrap items-center gap-2.5">
  <li><span class="inline-flex items-center rounded-full border border-transparent bg-[#dcfce7] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#166534]">Delivered</span></li>
  <li><span class="inline-flex items-center rounded-full border border-transparent bg-[#fef3c7] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#92400e]">Awaiting stock</span></li>
  <li><span class="inline-flex items-center rounded-full border border-transparent bg-[#fee2e2] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#991b1b]">Cancelled</span></li>
  <li><span class="inline-flex items-center rounded-full border border-transparent bg-[#dbeafe] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#1e40af]">Shipped</span></li>
  <li><span class="inline-flex items-center rounded-full border border-transparent bg-[#f1f5f9] px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#334155]">Archived</span></li>
</ul></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#526072] uppercase">Outline badges · job details</span>
<ul class="flex flex-wrap items-center gap-2.5">
  <li><span class="inline-flex items-center rounded-full border-[1.5px] border-current px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#4338ca]">Remote</span></li>
  <li><span class="inline-flex items-center rounded-full border-[1.5px] border-current px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#0f766e]">Full-time</span></li>
  <li><span class="inline-flex items-center rounded-full border-[1.5px] border-current px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#a14d07]">Contract</span></li>
  <li><span class="inline-flex items-center rounded-full border-[1.5px] border-current px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#be185d]">Senior</span></li>
  <li><span class="inline-flex items-center rounded-full border-[1.5px] border-current px-2.5 py-1 text-[.75rem] leading-[1.25] font-semibold tracking-[.01em] whitespace-nowrap text-[#334155]">Visa sponsored</span></li>
</ul></div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#526072] uppercase">Counts on icon and text buttons</span>
<div class="flex flex-wrap items-center gap-[22px]">
  <button class="relative inline-grid size-11 cursor-pointer place-items-center rounded-xl border border-[#cbd5e1] bg-white text-[#1e293b] transition-[background-color,border-color] duration-150 hover:border-[#94a3b8] hover:bg-[#f1f5f9] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] motion-reduce:transition-none" type="button"><svg class="size-[22px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9a6 6 0 1 1 12 0c0 6 2.5 8 2.5 8h-17S6 15 6 9"/><path d="M10.3 20.5a2 2 0 0 0 3.4 0"/></svg><span class="sr-only">Notifications,</span><span class="absolute top-0 left-full h-5 min-w-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-[#f8fafc] bg-[#dc2626] px-1.5 text-center text-[.68rem] leading-4 font-bold text-white">3<span class="sr-only"> unread</span></span></button>
  <button class="relative inline-grid size-11 cursor-pointer place-items-center rounded-xl border border-[#cbd5e1] bg-white text-[#1e293b] transition-[background-color,border-color] duration-150 hover:border-[#94a3b8] hover:bg-[#f1f5f9] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] motion-reduce:transition-none" type="button"><svg class="size-[22px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="2.5"/><path d="M3.5 7.5l8.5 6 8.5-6"/></svg><span class="sr-only">Messages,</span><span class="absolute top-0 left-full h-5 min-w-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-[#f8fafc] bg-[#dc2626] px-1.5 text-center text-[.68rem] leading-4 font-bold text-white">12<span class="sr-only"> unread</span></span></button>
  <button class="relative inline-grid size-11 cursor-pointer place-items-center rounded-xl border border-[#cbd5e1] bg-white text-[#1e293b] transition-[background-color,border-color] duration-150 hover:border-[#94a3b8] hover:bg-[#f1f5f9] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] motion-reduce:transition-none" type="button"><svg class="size-[22px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="9.5" cy="19.5" r="1.4"/><circle cx="17.5" cy="19.5" r="1.4"/><path d="M2.5 3.5h3l2.4 11a2 2 0 0 0 2 1.5h7.4a2 2 0 0 0 2-1.6L21 7.5H6.3"/></svg><span class="sr-only">Basket,</span><span class="absolute top-0 left-full h-5 min-w-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-[#f8fafc] bg-[#0f172a] px-1.5 text-center text-[.68rem] leading-4 font-bold text-white">2<span class="sr-only"> items</span></span></button>
  <button class="relative inline-grid size-11 cursor-pointer place-items-center rounded-xl border border-[#cbd5e1] bg-white text-[#1e293b] transition-[background-color,border-color] duration-150 hover:border-[#94a3b8] hover:bg-[#f1f5f9] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] motion-reduce:transition-none" type="button"><svg class="size-[22px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5v11m0 0l-4-4m4 4l4-4M4.5 16.5v2a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-2"/></svg><span class="sr-only">Updates,</span><span class="absolute top-0 left-full h-5 min-w-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-[#f8fafc] bg-[#dc2626] px-1.5 text-center text-[.68rem] leading-4 font-bold text-white">99+<span class="sr-only"> waiting</span></span></button>
  <button class="relative inline-grid size-11 cursor-pointer place-items-center rounded-xl border border-[#cbd5e1] bg-white text-[#1e293b] transition-[background-color,border-color] duration-150 hover:border-[#94a3b8] hover:bg-[#f1f5f9] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] motion-reduce:transition-none" type="button"><svg class="size-[22px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.5 12a8.5 8.5 0 0 1-12.3 7.6L3.5 21l1.4-4.5A8.5 8.5 0 1 1 20.5 12z"/></svg><span class="sr-only">Comments, new replies</span><span class="absolute top-1 right-1 size-3 rounded-full border-2 border-[#f8fafc] bg-[#dc2626]" aria-hidden="true"></span></button>
  <button class="inline-flex cursor-pointer items-center gap-2 rounded-[10px] border border-[#cbd5e1] bg-white px-3.5 py-[9px] text-[.9rem] font-semibold text-[#1e293b] transition-[background-color,border-color] duration-150 hover:bg-[#f1f5f9] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] motion-reduce:transition-none" type="button">Inbox <span class="rounded-full bg-[#e0e7ff] px-2 py-0.5 text-[.72rem] leading-[1.3] font-bold text-[#3730a3]">24<span class="sr-only"> new</span></span></button>
</div></div>
CSS
/* The pulse ring on the Live badge. Everything else is utility classes in the markup. */
@theme{--animate-bdg-ping:bdg-ping 1.6s ease-out infinite}
@keyframes bdg-ping{from{transform:scale(1);opacity:.6}to{transform:scale(2.6);opacity:0}}

About this set

The badges most interfaces need first, each shown with realistic content. Solid pills mark invoice states such as Paid, Pending, Overdue, Refunded and Draft, each with a small icon beside the word. Dot badges report service health on a neutral pill, with a coloured dot and a Live badge whose dot sends out a soft pulse. Soft badges use a pale tint with dark text of the same hue for order states, and outline badges carry job details such as Remote or Contract where a quieter label fits. The last row puts notification counts on icon buttons: 3 unread notifications, 12 messages, 2 basket items, a 99+ overflow, a dot-only indicator for new replies and a count inside a text button. Use solid pills where the status is the main thing on the row, soft or outline badges in dense tables, and dot badges for live system state. Every badge is a word, so colour is never the only signal, and each count carries visually hidden text so the button reads as Notifications, 3 unread.

What’s included

  • Solid, dot, soft and outline badge styles from one base class
  • Notification counts on icon buttons with hidden text such as 3 unread
  • A 99+ overflow count and a dot-only indicator with a text name
  • Live badge with a pulsing dot that stops under reduced motion
  • Every status is a word as well as a colour

Accessibility

Badges are plain text, so the status is read as a word and colour is never the only cue. Icon buttons have a visually hidden name and the count adds hidden context, for example Messages, 12 unread, and the dot-only indicator is named Comments, new replies. Buttons show a 2px indigo focus outline, and the pulse and hover transitions switch off under prefers-reduced-motion.

Customise it

In plain CSS each style is a modifier on .bdg that sets --bdg-bg, --bdg-fg and --bdg-line, and dot colours come from --dot. Bootstrap uses the same modifiers on .badge.rounded-pill with --bs-badge-* variables; in Tailwind change the bg-, text- and border- colour utilities on each badge.