Open demo

CSS code

HTML
<div><span class="lbl">Billing dashboard with status filters and search</span>
<section class="bl" data-invoices aria-labelledby="bl-title">
  <div class="bl-head">
    <div><h2 class="bl-title" id="bl-title">Invoices</h2><p class="bl-sub">Kinfolk Studio · figures in USD as of 19 Oct 2026</p></div>
    <a class="bl-btn" href="#new-invoice"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>New invoice</a>
  </div>
  <dl class="bl-stats"><div class="bl-stat"><dt class="bl-statk">Outstanding</dt><dd class="bl-statv">$11,975.50</dd><dd class="bl-stats-sub">4 invoices due or overdue</dd></div><div class="bl-stat bl-stat--over"><dt class="bl-statk">Overdue</dt><dd class="bl-statv">$7,725.50</dd><dd class="bl-stats-sub">3 invoices, oldest 30 days</dd></div><div class="bl-stat"><dt class="bl-statk">Paid, last 60 days</dt><dd class="bl-statv">$3,105.00</dd><dd class="bl-stats-sub">4 invoices</dd></div><div class="bl-stat"><dt class="bl-statk">Drafts</dt><dd class="bl-statv">$5,600.00</dd><dd class="bl-stats-sub">1 invoice not sent</dd></div></dl>
  <div class="bl-toolbar" data-toolbar hidden>
    <div class="bl-segs" role="group" aria-label="Filter by status"><button class="bl-seg" type="button" data-filter="all" aria-pressed="true">All</button><button class="bl-seg" type="button" data-filter="open" aria-pressed="false">Due</button><button class="bl-seg" type="button" data-filter="overdue" aria-pressed="false">Overdue</button><button class="bl-seg" type="button" data-filter="paid" aria-pressed="false">Paid</button><button class="bl-seg" type="button" data-filter="draft" aria-pressed="false">Draft</button></div>
    <div class="bl-searchwrap"><label class="sr-only" for="bl-search">Search invoices by client or number</label>
      <svg class="bl-searchicon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="6.5"/><path d="M16 16l4.5 4.5"/></svg>
      <input class="bl-search" id="bl-search" type="search" placeholder="Search client or number" data-search autocomplete="off"></div>
  </div>
  <div class="bl-scroll" role="region" aria-labelledby="bl-caption" tabindex="0">
    <table class="bl-table">
      <caption class="sr-only" id="bl-caption">Invoices, newest first</caption>
      <thead><tr class=""><th scope="col">Invoice</th><th scope="col">Client</th><th scope="col">Issued</th><th scope="col">Due</th><th scope="col" class="bl-right">Amount</th><th scope="col">Status</th><th scope="col" class="bl-right"><span class="sr-only">Actions</span></th></tr></thead>
      <tbody>
        <tr data-status="draft" data-amount="560000" class=""><th scope="row" class="bl-num">INV-2042</th><td class="">Fieldstone Architects</td><td class=" bl-muted">—</td><td class=" bl-muted">—</td><td class=" bl-right">$5,600.00</td><td class=""><span class="bl-pill bl-pill--draft"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20h4L19 9l-4-4L4 16z"/><path d="M13.5 6.5l4 4"/></svg>Draft</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2042">Edit<span class="sr-only"> INV-2042</span></a></td></tr>
        <tr data-status="open" data-amount="425000" class=""><th scope="row" class="bl-num">INV-2041</th><td class="">Harbor & Vine Winery</td><td class=" bl-muted">2 Oct 2026</td><td class=" bl-muted">1 Nov 2026</td><td class=" bl-right">$4,250.00</td><td class=""><span class="bl-pill bl-pill--open"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></svg>Due</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2041">View<span class="sr-only"> INV-2041</span></a></td></tr>
        <tr data-status="paid" data-amount="118000" class=""><th scope="row" class="bl-num">INV-2040</th><td class="">Copperleaf Dental</td><td class=" bl-muted">28 Sep 2026</td><td class=" bl-muted">28 Oct 2026</td><td class=" bl-right">$1,180.00</td><td class=""><span class="bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2040">View<span class="sr-only"> INV-2040</span></a></td></tr>
        <tr data-status="overdue" data-amount="264000" class=""><th scope="row" class="bl-num">INV-2039</th><td class="">Northgate Fitness</td><td class=" bl-muted">15 Sep 2026</td><td class=" bl-muted">15 Oct 2026</td><td class=" bl-right">$2,640.00</td><td class=""><span class="bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2039">View<span class="sr-only"> INV-2039</span></a></td></tr>
        <tr data-status="paid" data-amount="39500" class=""><th scope="row" class="bl-num">INV-2038</th><td class="">Bluebell Florist</td><td class=" bl-muted">12 Sep 2026</td><td class=" bl-muted">12 Oct 2026</td><td class=" bl-right">$395.00</td><td class=""><span class="bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2038">View<span class="sr-only"> INV-2038</span></a></td></tr>
        <tr data-status="overdue" data-amount="387050" class=""><th scope="row" class="bl-num">INV-2037</th><td class="">Atlas Removals</td><td class=" bl-muted">3 Sep 2026</td><td class=" bl-muted">3 Oct 2026</td><td class=" bl-right">$3,870.50</td><td class=""><span class="bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2037">View<span class="sr-only"> INV-2037</span></a></td></tr>
        <tr data-status="paid" data-amount="64000" class=""><th scope="row" class="bl-num">INV-2036</th><td class="">Quayside Books</td><td class=" bl-muted">1 Sep 2026</td><td class=" bl-muted">1 Oct 2026</td><td class=" bl-right">$640.00</td><td class=""><span class="bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2036">View<span class="sr-only"> INV-2036</span></a></td></tr>
        <tr data-status="overdue" data-amount="121500" class=""><th scope="row" class="bl-num">INV-2035</th><td class="">Saltmarsh Surf School</td><td class=" bl-muted">20 Aug 2026</td><td class=" bl-muted">19 Sep 2026</td><td class=" bl-right">$1,215.00</td><td class=""><span class="bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2035">View<span class="sr-only"> INV-2035</span></a></td></tr>
        <tr data-status="paid" data-amount="89000" class=""><th scope="row" class="bl-num">INV-2034</th><td class="">Redkite Coffee</td><td class=" bl-muted">18 Aug 2026</td><td class=" bl-muted">17 Sep 2026</td><td class=" bl-right">$890.00</td><td class=""><span class="bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" bl-right"><a class="bl-link" href="#inv-2034">View<span class="sr-only"> INV-2034</span></a></td></tr>
        <tr data-empty hidden><td colspan="7" class="bl-empty">No invoices match this filter.</td></tr>
      </tbody>
      <tfoot><tr class=""><th scope="row" colspan="4" data-count>Showing 9 of 9</th><td class="bl-right" data-sum>$20,680.50</td><td colspan="2"></td></tr></tfoot>
    </table>
  </div>
  <p class="sr-only" role="status" data-status-msg></p>
</section>
</div>
<div><span class="lbl">Recent invoices card for a sidebar</span>
<section class="bl bl--narrow" aria-labelledby="bl2-title">
  <div class="bl-rhead"><h2 class="bl-h3" id="bl2-title">Recent invoices</h2><a class="bl-link" href="#all-invoices">View all<span class="sr-only"> invoices</span></a></div>
  <ul class="bl-rlist">
      <li class="bl-ritem"><div class="bl-rmain"><a class="bl-rclient" href="#inv-2041">Harbor & Vine Winery</a><p class="bl-rmeta">INV-2041 · Due 1 Nov 2026</p></div><div class="bl-rside"><p class="bl-ramt">$4,250.00</p><span class="bl-pill bl-pill--open"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></svg>Due</span></div></li>
      <li class="bl-ritem"><div class="bl-rmain"><a class="bl-rclient" href="#inv-2040">Copperleaf Dental</a><p class="bl-rmeta">INV-2040 · Paid</p></div><div class="bl-rside"><p class="bl-ramt">$1,180.00</p><span class="bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></div></li>
      <li class="bl-ritem"><div class="bl-rmain"><a class="bl-rclient" href="#inv-2039">Northgate Fitness</a><p class="bl-rmeta">INV-2039 · Was due 15 Oct 2026</p></div><div class="bl-rside"><p class="bl-ramt">$2,640.00</p><span class="bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></div></li>
      <li class="bl-ritem"><div class="bl-rmain"><a class="bl-rclient" href="#inv-2038">Bluebell Florist</a><p class="bl-rmeta">INV-2038 · Paid</p></div><div class="bl-rside"><p class="bl-ramt">$395.00</p><span class="bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></div></li>
      <li class="bl-ritem"><div class="bl-rmain"><a class="bl-rclient" href="#inv-2037">Atlas Removals</a><p class="bl-rmeta">INV-2037 · Was due 3 Oct 2026</p></div><div class="bl-rside"><p class="bl-ramt">$3,870.50</p><span class="bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></div></li>
      </ul>
</section>
</div>
CSS
/* Invoice list / billing dashboard. Status pills always carry a word and an icon, never colour alone. The table
   sits in a labelled, focusable scroll region on narrow screens; filters are aria-pressed toggle buttons. */
.bl{--bl-accent:#1d4ed8;--bl-accent-dark:#1e40af;--bl-ink:#172033;--bl-muted:#525c6e;--bl-line:#e2e6ee;--bl-edge:#7d8698;--bl-soft:#f5f7fb;
  box-sizing:border-box;background:#fff;color:var(--bl-ink);border-radius:18px;padding:28px;font-size:14px;line-height:1.45;
  box-shadow:0 1px 2px rgba(23,32,51,.06),0 24px 48px -30px rgba(23,32,51,.35)}
.bl *,.bl *::before,.bl *::after{box-sizing:border-box}
:where(.bl) :is(h2,p,dl,dd,ul,table){margin:0}
.bl .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}
.bl :where(button,input){font:inherit;color:inherit}
.bl :is(a,button,input,.bl-scroll):focus-visible{outline:2px solid var(--bl-accent);outline-offset:2px}
.bl-head{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:22px}
.bl-title{font-size:1.45rem;font-weight:700;letter-spacing:-.01em}
.bl-sub{color:var(--bl-muted);font-size:.86rem;margin-top:2px}
.bl-btn{display:inline-flex;align-items:center;gap:8px;padding:10px 16px;border-radius:10px;background:var(--bl-accent);color:#fff;font-weight:700;text-decoration:none;transition:background-color .15s}
.bl-btn:hover{background:var(--bl-accent-dark)}
.bl-stats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-bottom:22px}
.bl-stat{padding:14px 16px;border:1px solid var(--bl-line);border-radius:14px;background:var(--bl-soft)}
.bl-stat--over{border-color:#f3c4c0;background:#fef4f3}
.bl-statk{font-size:.8rem;font-weight:600;color:var(--bl-muted)}
.bl-statv{font-size:1.35rem;font-weight:800;letter-spacing:-.01em;font-variant-numeric:tabular-nums;margin-top:2px}
.bl-stat--over .bl-statv{color:#b42318}
.bl-stats-sub{font-size:.78rem;color:var(--bl-muted)}
.bl-toolbar{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;margin-bottom:14px}
.bl-toolbar[hidden]{display:none}
.bl-segs{display:flex;flex-wrap:wrap;gap:4px;padding:4px;border-radius:12px;background:#eef1f6}
.bl-seg{padding:7px 13px;border:0;border-radius:9px;background:none;color:var(--bl-muted);font-weight:600;font-size:.86rem;cursor:pointer;transition:background-color .15s,color .15s}
.bl-seg:hover{color:var(--bl-ink)}
.bl-seg[aria-pressed="true"]{background:#fff;color:var(--bl-ink);box-shadow:0 1px 2px rgba(23,32,51,.12),0 0 0 1px var(--bl-line)}
.bl-searchwrap{position:relative;flex:0 1 260px}
.bl-searchicon{position:absolute;left:11px;top:50%;transform:translateY(-50%);color:var(--bl-muted);pointer-events:none}
.bl-search{width:100%;min-height:40px;padding:8px 12px 8px 34px;border:1px solid var(--bl-edge);border-radius:10px;background:#fff}
.bl-search::placeholder{color:#626b7c}
.bl-search:focus{border-color:var(--bl-accent);box-shadow:0 0 0 3px rgba(29,78,216,.2)}
.bl-scroll{position:relative;overflow-x:auto;border:1px solid var(--bl-line);border-radius:14px}
.bl-table{width:100%;min-width:720px;border-collapse:collapse;font-variant-numeric:tabular-nums}
.bl-table thead th{padding:11px 14px;background:var(--bl-soft);border-bottom:1px solid var(--bl-line);font-size:.75rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--bl-muted);text-align:left;white-space:nowrap}
.bl-table tbody :is(th,td){padding:13px 14px;border-bottom:1px solid var(--bl-line);text-align:left;white-space:nowrap}
.bl-table tbody tr:hover{background:#fafbfd}
.bl-num{font-weight:700}
.bl-muted{color:var(--bl-muted)}
.bl-table .bl-right{text-align:right}
.bl-table tfoot :is(th,td){padding:12px 14px;font-weight:700;text-align:left}
.bl-table tfoot th{color:var(--bl-muted);font-weight:600}
.bl-table tfoot .bl-right{text-align:right}
.bl-empty{text-align:center!important;color:var(--bl-muted);padding:28px!important}
.bl-pill{display:inline-flex;align-items:center;gap:5px;padding:3px 10px 3px 8px;border-radius:999px;font-size:.78rem;font-weight:700;border:1px solid}
.bl-pill--paid{background:#ecfdf3;color:#166534;border-color:#a6dfbb}
.bl-pill--open{background:#eff4ff;color:#1e40af;border-color:#b6c8f5}
.bl-pill--overdue{background:#fef3f2;color:#b42318;border-color:#f3b8b2}
.bl-pill--draft{background:#f2f4f7;color:#475467;border-color:#cfd4dc}
.bl-link{color:var(--bl-accent);font-weight:600;text-decoration:none}
.bl-link:hover{text-decoration:underline}
/* recent list */
.bl--narrow{max-width:420px;padding:22px}
.bl-rhead{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:8px}
.bl-h3{font-size:1.1rem;font-weight:700}
.bl-rlist{list-style:none;padding:0}
.bl-ritem{display:flex;justify-content:space-between;gap:12px;padding:12px 0;border-top:1px solid var(--bl-line)}
.bl-rmain{min-width:0}
.bl-rclient{color:var(--bl-ink);font-weight:600;text-decoration:none}
.bl-rclient:hover{text-decoration:underline}
.bl-rmeta{font-size:.8rem;color:var(--bl-muted)}
.bl-rside{display:grid;justify-items:end;gap:4px;flex:none}
.bl-ramt{font-weight:700;font-variant-numeric:tabular-nums}
@media (max-width:760px){.bl-stats{grid-template-columns:1fr 1fr}}
@media (max-width:480px){.bl{padding:20px 16px}.bl-statv{font-size:1.15rem}.bl-searchwrap{flex:1 1 100%}}
@media (prefers-reduced-motion:reduce){.bl-btn,.bl-seg{transition:none}}
JavaScript
// Status filter and search for the invoice table. Each row carries data-status and data-amount (in cents);
// the footer shows how many rows are visible and their total, and the status line is announced politely.
document.querySelectorAll('[data-invoices]').forEach(function (root) {
  var rows = Array.prototype.slice.call(root.querySelectorAll('tbody tr[data-status]'));
  var buttons = root.querySelectorAll('[data-filter]');
  var search = root.querySelector('[data-search]');
  var toolbar = root.querySelector('[data-toolbar]');
  var count = root.querySelector('[data-count]');
  var sum = root.querySelector('[data-sum]');
  var empty = root.querySelector('[data-empty]');
  var status = root.querySelector('[data-status-msg]');
  var fmt = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
  var filter = 'all', timer;
  if (toolbar) toolbar.hidden = false;

  function apply(announce) {
    var q = search ? search.value.trim().toLowerCase() : '', shown = 0, total = 0;
    rows.forEach(function (row) {
      var ok = (filter === 'all' || row.dataset.status === filter) && (!q || row.textContent.toLowerCase().indexOf(q) > -1);
      row.hidden = !ok;
      if (ok) { shown += 1; total += +row.dataset.amount; }
    });
    var label = shown + (shown === 1 ? ' invoice' : ' invoices');
    count.textContent = 'Showing ' + shown + ' of ' + rows.length;
    sum.textContent = fmt.format(total / 100);
    if (empty) empty.hidden = shown > 0;
    if (announce && status) status.textContent = label + ', ' + fmt.format(total / 100) + '.';
  }
  buttons.forEach(function (btn) {
    btn.addEventListener('click', function () {
      filter = btn.dataset.filter;
      buttons.forEach(function (b) { b.setAttribute('aria-pressed', String(b === btn)); });
      apply(true);
    });
  });
  if (search) search.addEventListener('input', function () { clearTimeout(timer); apply(false); timer = setTimeout(function () { apply(true); }, 500); });
  apply(false);
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Billing dashboard with status filters and search</span>
<section class="bl card" data-invoices aria-labelledby="bl-title">
  <div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-4">
    <div><h2 class="bl-title" id="bl-title">Invoices</h2><p class="bl-sub">Kinfolk Studio · figures in USD as of 19 Oct 2026</p></div>
    <a class="btn btn-primary bl-btn" href="#new-invoice"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>New invoice</a>
  </div>
  <dl class="d-grid gap-3 mb-4 bl-stats"><div class="bl-stat"><dt class="bl-statk">Outstanding</dt><dd class="bl-statv">$11,975.50</dd><dd class="bl-stats-sub">4 invoices due or overdue</dd></div><div class="bl-stat bl-stat--over"><dt class="bl-statk">Overdue</dt><dd class="bl-statv">$7,725.50</dd><dd class="bl-stats-sub">3 invoices, oldest 30 days</dd></div><div class="bl-stat"><dt class="bl-statk">Paid, last 60 days</dt><dd class="bl-statv">$3,105.00</dd><dd class="bl-stats-sub">4 invoices</dd></div><div class="bl-stat"><dt class="bl-statk">Drafts</dt><dd class="bl-statv">$5,600.00</dd><dd class="bl-stats-sub">1 invoice not sent</dd></div></dl>
  <div class="bl-toolbar mb-3" data-toolbar hidden>
    <div class="btn-group bl-segs flex-wrap" role="group" aria-label="Filter by status"><button class="btn bl-seg" type="button" data-filter="all" aria-pressed="true">All</button><button class="btn bl-seg" type="button" data-filter="open" aria-pressed="false">Due</button><button class="btn bl-seg" type="button" data-filter="overdue" aria-pressed="false">Overdue</button><button class="btn bl-seg" type="button" data-filter="paid" aria-pressed="false">Paid</button><button class="btn bl-seg" type="button" data-filter="draft" aria-pressed="false">Draft</button></div>
    <div class="bl-searchwrap position-relative"><label class="visually-hidden" for="bl-search">Search invoices by client or number</label>
      <svg class="bl-searchicon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="6.5"/><path d="M16 16l4.5 4.5"/></svg>
      <input class="form-control bl-search" id="bl-search" type="search" placeholder="Search client or number" data-search autocomplete="off"></div>
  </div>
  <div class="table-responsive bl-scroll position-relative" role="region" aria-labelledby="bl-caption" tabindex="0">
    <table class="table table-hover align-middle mb-0 bl-table">
      <caption class="visually-hidden" id="bl-caption">Invoices, newest first</caption>
      <thead><tr class=""><th scope="col">Invoice</th><th scope="col">Client</th><th scope="col">Issued</th><th scope="col">Due</th><th scope="col" class="text-end">Amount</th><th scope="col">Status</th><th scope="col" class="text-end"><span class="visually-hidden">Actions</span></th></tr></thead>
      <tbody>
        <tr data-status="draft" data-amount="560000" class=""><th scope="row" class="bl-num">INV-2042</th><td class="">Fieldstone Architects</td><td class=" bl-muted">—</td><td class=" bl-muted">—</td><td class=" text-end">$5,600.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--draft"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20h4L19 9l-4-4L4 16z"/><path d="M13.5 6.5l4 4"/></svg>Draft</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2042">Edit<span class="visually-hidden"> INV-2042</span></a></td></tr>
        <tr data-status="open" data-amount="425000" class=""><th scope="row" class="bl-num">INV-2041</th><td class="">Harbor & Vine Winery</td><td class=" bl-muted">2 Oct 2026</td><td class=" bl-muted">1 Nov 2026</td><td class=" text-end">$4,250.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--open"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></svg>Due</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2041">View<span class="visually-hidden"> INV-2041</span></a></td></tr>
        <tr data-status="paid" data-amount="118000" class=""><th scope="row" class="bl-num">INV-2040</th><td class="">Copperleaf Dental</td><td class=" bl-muted">28 Sep 2026</td><td class=" bl-muted">28 Oct 2026</td><td class=" text-end">$1,180.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2040">View<span class="visually-hidden"> INV-2040</span></a></td></tr>
        <tr data-status="overdue" data-amount="264000" class=""><th scope="row" class="bl-num">INV-2039</th><td class="">Northgate Fitness</td><td class=" bl-muted">15 Sep 2026</td><td class=" bl-muted">15 Oct 2026</td><td class=" text-end">$2,640.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2039">View<span class="visually-hidden"> INV-2039</span></a></td></tr>
        <tr data-status="paid" data-amount="39500" class=""><th scope="row" class="bl-num">INV-2038</th><td class="">Bluebell Florist</td><td class=" bl-muted">12 Sep 2026</td><td class=" bl-muted">12 Oct 2026</td><td class=" text-end">$395.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2038">View<span class="visually-hidden"> INV-2038</span></a></td></tr>
        <tr data-status="overdue" data-amount="387050" class=""><th scope="row" class="bl-num">INV-2037</th><td class="">Atlas Removals</td><td class=" bl-muted">3 Sep 2026</td><td class=" bl-muted">3 Oct 2026</td><td class=" text-end">$3,870.50</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2037">View<span class="visually-hidden"> INV-2037</span></a></td></tr>
        <tr data-status="paid" data-amount="64000" class=""><th scope="row" class="bl-num">INV-2036</th><td class="">Quayside Books</td><td class=" bl-muted">1 Sep 2026</td><td class=" bl-muted">1 Oct 2026</td><td class=" text-end">$640.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2036">View<span class="visually-hidden"> INV-2036</span></a></td></tr>
        <tr data-status="overdue" data-amount="121500" class=""><th scope="row" class="bl-num">INV-2035</th><td class="">Saltmarsh Surf School</td><td class=" bl-muted">20 Aug 2026</td><td class=" bl-muted">19 Sep 2026</td><td class=" text-end">$1,215.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2035">View<span class="visually-hidden"> INV-2035</span></a></td></tr>
        <tr data-status="paid" data-amount="89000" class=""><th scope="row" class="bl-num">INV-2034</th><td class="">Redkite Coffee</td><td class=" bl-muted">18 Aug 2026</td><td class=" bl-muted">17 Sep 2026</td><td class=" text-end">$890.00</td><td class=""><span class="badge rounded-pill bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-end"><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#inv-2034">View<span class="visually-hidden"> INV-2034</span></a></td></tr>
        <tr data-empty hidden><td colspan="7" class="bl-empty">No invoices match this filter.</td></tr>
      </tbody>
      <tfoot><tr class=""><th scope="row" colspan="4" data-count>Showing 9 of 9</th><td class="text-end" data-sum>$20,680.50</td><td colspan="2"></td></tr></tfoot>
    </table>
  </div>
  <p class="visually-hidden" role="status" data-status-msg></p>
</section>
</div>
<div><span class="lbl">Recent invoices card for a sidebar</span>
<section class="bl card bl--narrow" aria-labelledby="bl2-title">
  <div class="d-flex justify-content-between align-items-baseline mb-2"><h2 class="bl-h3" id="bl2-title">Recent invoices</h2><a class="link-primary link-underline-opacity-0 link-underline-opacity-100-hover fw-semibold bl-link" href="#all-invoices">View all<span class="visually-hidden"> invoices</span></a></div>
  <ul class="list-group list-group-flush bl-rlist">
      <li class="list-group-item d-flex justify-content-between gap-3 px-0 py-3"><div class="text-truncate"><a class="bl-rclient" href="#inv-2041">Harbor & Vine Winery</a><p class="small text-body-secondary mb-0">INV-2041 · Due 1 Nov 2026</p></div><div class="d-grid justify-items-end gap-1 flex-shrink-0 text-end bl-rside"><p class="fw-bold bl-ramt mb-0">$4,250.00</p><span class="badge rounded-pill bl-pill bl-pill--open"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></svg>Due</span></div></li>
      <li class="list-group-item d-flex justify-content-between gap-3 px-0 py-3"><div class="text-truncate"><a class="bl-rclient" href="#inv-2040">Copperleaf Dental</a><p class="small text-body-secondary mb-0">INV-2040 · Paid</p></div><div class="d-grid justify-items-end gap-1 flex-shrink-0 text-end bl-rside"><p class="fw-bold bl-ramt mb-0">$1,180.00</p><span class="badge rounded-pill bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></div></li>
      <li class="list-group-item d-flex justify-content-between gap-3 px-0 py-3"><div class="text-truncate"><a class="bl-rclient" href="#inv-2039">Northgate Fitness</a><p class="small text-body-secondary mb-0">INV-2039 · Was due 15 Oct 2026</p></div><div class="d-grid justify-items-end gap-1 flex-shrink-0 text-end bl-rside"><p class="fw-bold bl-ramt mb-0">$2,640.00</p><span class="badge rounded-pill bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></div></li>
      <li class="list-group-item d-flex justify-content-between gap-3 px-0 py-3"><div class="text-truncate"><a class="bl-rclient" href="#inv-2038">Bluebell Florist</a><p class="small text-body-secondary mb-0">INV-2038 · Paid</p></div><div class="d-grid justify-items-end gap-1 flex-shrink-0 text-end bl-rside"><p class="fw-bold bl-ramt mb-0">$395.00</p><span class="badge rounded-pill bl-pill bl-pill--paid"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></div></li>
      <li class="list-group-item d-flex justify-content-between gap-3 px-0 py-3"><div class="text-truncate"><a class="bl-rclient" href="#inv-2037">Atlas Removals</a><p class="small text-body-secondary mb-0">INV-2037 · Was due 3 Oct 2026</p></div><div class="d-grid justify-items-end gap-1 flex-shrink-0 text-end bl-rside"><p class="fw-bold bl-ramt mb-0">$3,870.50</p><span class="badge rounded-pill bl-pill bl-pill--overdue"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></div></li>
      </ul>
</section>
</div>
CSS
/* Bootstrap .card, .row/.col, .btn-group of aria-pressed .btn toggles, .form-control, .table-hover in .table-responsive,
   .badge pills and a .list-group, retuned through Bootstrap's CSS variables. Pills always carry a word and an icon. */
.bl{--bl-accent:#1d4ed8;--bl-accent-dark:#1e40af;--bl-ink:#172033;--bl-muted:#525c6e;--bl-line:#e2e6ee;--bl-edge:#7d8698;--bl-soft:#f5f7fb;
  --bs-card-border-width:0;--bs-card-border-radius:18px;--bs-body-color:var(--bl-ink);--bs-secondary-color:var(--bl-muted);--bs-border-color:var(--bl-line);
  --bs-link-color-rgb:29,78,216;--bs-link-hover-color-rgb:30,64,175;--bs-primary-rgb:29,78,216;
  color:var(--bl-ink);padding:28px;font-size:14px;line-height:1.45;box-shadow:0 1px 2px rgba(23,32,51,.06),0 24px 48px -30px rgba(23,32,51,.35)}
.bl :is(h2,p,dl,dd){margin:0}
.bl :is(a,.btn,.form-control,.bl-scroll):focus-visible{outline:2px solid var(--bl-accent);outline-offset:2px;box-shadow:none}
.bl-title{font-size:1.45rem;font-weight:700;letter-spacing:-.01em}
.bl-sub{color:var(--bl-muted);font-size:.86rem;margin-top:2px!important}
.bl-btn{--bs-btn-bg:var(--bl-accent);--bs-btn-border-color:var(--bl-accent);--bs-btn-hover-bg:var(--bl-accent-dark);--bs-btn-hover-border-color:var(--bl-accent-dark);--bs-btn-font-weight:700;
  --bs-btn-border-radius:10px;--bs-btn-padding-x:16px;--bs-btn-padding-y:10px;--bs-btn-font-size:inherit;display:inline-flex;align-items:center;gap:8px}
.bl-stats{grid-template-columns:repeat(4,minmax(0,1fr))}
.bl-stat{padding:14px 16px;border:1px solid var(--bl-line);border-radius:14px;background:var(--bl-soft)}
.bl-stat--over{border-color:#f3c4c0;background:#fef4f3}
.bl-toolbar{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px}
@media (max-width:760px){.bl-stats{grid-template-columns:1fr 1fr}}
.bl-statk{font-size:.8rem;font-weight:600;color:var(--bl-muted)}
.bl-statv{font-size:1.35rem;font-weight:800;letter-spacing:-.01em;font-variant-numeric:tabular-nums;padding-top:2px!important}
.bl-stat--over .bl-statv{color:#b42318}
.bl-stats-sub{font-size:.78rem;color:var(--bl-muted)}
.bl-segs{gap:4px;padding:4px;border-radius:12px;background:#eef1f6}
.bl-seg{--bs-btn-color:var(--bl-muted);--bs-btn-hover-color:var(--bl-ink);--bs-btn-active-color:var(--bl-ink);--bs-btn-active-bg:#fff;--bs-btn-border-width:0;--bs-btn-font-weight:600;
  --bs-btn-font-size:.86rem;--bs-btn-padding-x:13px;--bs-btn-padding-y:7px;border-radius:9px!important;margin:0!important}
.bl-seg[aria-pressed="true"]{background:#fff;color:var(--bl-ink);box-shadow:0 1px 2px rgba(23,32,51,.12),0 0 0 1px var(--bl-line)}
.bl-searchwrap{flex:0 1 260px}
.bl-searchicon{position:absolute;left:11px;top:50%;transform:translateY(-50%);color:var(--bl-muted);pointer-events:none}
.bl-search{--bs-border-color:var(--bl-edge);font-size:inherit;min-height:40px;padding:8px 12px 8px 34px;border-radius:10px}
.bl-search::placeholder{color:#626b7c}
.bl-search:focus{border-color:var(--bl-accent);box-shadow:0 0 0 3px rgba(29,78,216,.2)}
.bl-scroll{border:1px solid var(--bl-line);border-radius:14px}
.bl-table{--bs-table-bg:transparent;--bs-table-hover-bg:#fafbfd;--bs-table-color:var(--bl-ink);--bs-table-border-color:var(--bl-line);min-width:720px;font-variant-numeric:tabular-nums}
.bl-table thead th{padding:11px 14px;background:var(--bl-soft);font-size:.75rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--bl-muted);white-space:nowrap}
.bl-table tbody>tr>*{padding:13px 14px;white-space:nowrap}
.bl-table tfoot>tr>*{padding:12px 14px;border-bottom:0;font-weight:700}
.bl-table tfoot th{color:var(--bl-muted);font-weight:600}
.bl-num{font-weight:700}
.bl-muted{color:var(--bl-muted)!important}
.bl-empty{text-align:center;color:var(--bl-muted)!important;padding:28px!important}
.bl-pill{--bs-badge-font-size:.78rem;--bs-badge-font-weight:700;--bs-badge-padding-x:10px;--bs-badge-padding-y:4px;display:inline-flex;align-items:center;gap:5px;padding-left:8px;border:1px solid}
.bl-pill--paid{background:#ecfdf3;color:#166534;border-color:#a6dfbb}
.bl-pill--open{background:#eff4ff;color:#1e40af;border-color:#b6c8f5}
.bl-pill--overdue{background:#fef3f2;color:#b42318;border-color:#f3b8b2}
.bl-pill--draft{background:#f2f4f7;color:#475467;border-color:#cfd4dc}
.bl--narrow{max-width:420px;padding:22px}
.bl-h3{font-size:1.1rem;font-weight:700}
.bl-rlist{--bs-list-group-bg:transparent;--bs-list-group-border-color:var(--bl-line);--bs-list-group-color:var(--bl-ink);border-top:1px solid var(--bl-line)}
.bl-rclient{color:var(--bl-ink);font-weight:600;text-decoration:none}
.bl-rclient:hover{text-decoration:underline}
.bl-rside{justify-items:end}
.bl-ramt{font-variant-numeric:tabular-nums}
@media (max-width:480px){.bl{padding:20px 16px}.bl-statv{font-size:1.15rem}.bl-searchwrap{flex:1 1 100%}}
@media (prefers-reduced-motion:reduce){.bl .btn{transition:none}}
JavaScript
// Status filter and search for the invoice table. Each row carries data-status and data-amount (in cents);
// the footer shows how many rows are visible and their total, and the status line is announced politely.
document.querySelectorAll('[data-invoices]').forEach(function (root) {
  var rows = Array.prototype.slice.call(root.querySelectorAll('tbody tr[data-status]'));
  var buttons = root.querySelectorAll('[data-filter]');
  var search = root.querySelector('[data-search]');
  var toolbar = root.querySelector('[data-toolbar]');
  var count = root.querySelector('[data-count]');
  var sum = root.querySelector('[data-sum]');
  var empty = root.querySelector('[data-empty]');
  var status = root.querySelector('[data-status-msg]');
  var fmt = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
  var filter = 'all', timer;
  if (toolbar) toolbar.hidden = false;

  function apply(announce) {
    var q = search ? search.value.trim().toLowerCase() : '', shown = 0, total = 0;
    rows.forEach(function (row) {
      var ok = (filter === 'all' || row.dataset.status === filter) && (!q || row.textContent.toLowerCase().indexOf(q) > -1);
      row.hidden = !ok;
      if (ok) { shown += 1; total += +row.dataset.amount; }
    });
    var label = shown + (shown === 1 ? ' invoice' : ' invoices');
    count.textContent = 'Showing ' + shown + ' of ' + rows.length;
    sum.textContent = fmt.format(total / 100);
    if (empty) empty.hidden = shown > 0;
    if (announce && status) status.textContent = label + ', ' + fmt.format(total / 100) + '.';
  }
  buttons.forEach(function (btn) {
    btn.addEventListener('click', function () {
      filter = btn.dataset.filter;
      buttons.forEach(function (b) { b.setAttribute('aria-pressed', String(b === btn)); });
      apply(true);
    });
  });
  if (search) search.addEventListener('input', function () { clearTimeout(timer); apply(false); timer = setTimeout(function () { apply(true); }, 500); });
  apply(false);
});

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525c6e] uppercase">Billing dashboard with status filters and search</span>
<section class="rounded-[18px] bg-white p-7 text-[14px] leading-[1.45] text-bl-ink shadow-[0_1px_2px_rgba(23,32,51,.06),0_24px_48px_-30px_rgba(23,32,51,.35)] max-[480px]:px-4 max-[480px]:py-5" data-invoices aria-labelledby="bl-title">
  <div class="mb-[22px] flex flex-wrap items-start justify-between gap-4">
    <div><h2 class="text-[1.45rem] font-bold tracking-[-.01em]" id="bl-title">Invoices</h2><p class="mt-0.5 text-[.86rem] text-bl-muted">Kinfolk Studio · figures in USD as of 19 Oct 2026</p></div>
    <a class="inline-flex items-center gap-2 rounded-[10px] bg-bl-accent px-4 py-2.5 font-bold text-white transition-colors duration-150 hover:bg-bl-accent-dark motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#new-invoice"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>New invoice</a>
  </div>
  <dl class="mb-[22px] grid grid-cols-4 gap-3 max-[760px]:grid-cols-2"><div class="rounded-[14px] border border-bl-line bg-bl-soft px-4 py-3.5"><dt class="text-[.8rem] font-semibold text-bl-muted">Outstanding</dt><dd class="mt-0.5 text-[1.35rem] font-extrabold tracking-[-.01em] tabular-nums max-[480px]:text-[1.15rem]">$11,975.50</dd><dd class="text-[.78rem] text-bl-muted">4 invoices due or overdue</dd></div><div class="rounded-[14px] border border-bl-line bg-bl-soft px-4 py-3.5 border-[#f3c4c0]! bg-[#fef4f3]! [&_dd:nth-of-type(1)]:text-[#b42318]"><dt class="text-[.8rem] font-semibold text-bl-muted">Overdue</dt><dd class="mt-0.5 text-[1.35rem] font-extrabold tracking-[-.01em] tabular-nums max-[480px]:text-[1.15rem]">$7,725.50</dd><dd class="text-[.78rem] text-bl-muted">3 invoices, oldest 30 days</dd></div><div class="rounded-[14px] border border-bl-line bg-bl-soft px-4 py-3.5"><dt class="text-[.8rem] font-semibold text-bl-muted">Paid, last 60 days</dt><dd class="mt-0.5 text-[1.35rem] font-extrabold tracking-[-.01em] tabular-nums max-[480px]:text-[1.15rem]">$3,105.00</dd><dd class="text-[.78rem] text-bl-muted">4 invoices</dd></div><div class="rounded-[14px] border border-bl-line bg-bl-soft px-4 py-3.5"><dt class="text-[.8rem] font-semibold text-bl-muted">Drafts</dt><dd class="mt-0.5 text-[1.35rem] font-extrabold tracking-[-.01em] tabular-nums max-[480px]:text-[1.15rem]">$5,600.00</dd><dd class="text-[.78rem] text-bl-muted">1 invoice not sent</dd></div></dl>
  <div class="mb-3.5 flex flex-wrap items-center justify-between gap-3" data-toolbar hidden>
    <div class="flex flex-wrap gap-1 rounded-xl bg-[#eef1f6] p-1" role="group" aria-label="Filter by status"><button class="cursor-pointer rounded-[9px] px-[13px] py-[7px] text-[.86rem] font-semibold text-bl-muted transition-colors duration-150 hover:text-bl-ink aria-pressed:bg-white aria-pressed:text-bl-ink aria-pressed:shadow-[0_1px_2px_rgba(23,32,51,.12),0_0_0_1px_var(--color-bl-line)] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" type="button" data-filter="all" aria-pressed="true">All</button><button class="cursor-pointer rounded-[9px] px-[13px] py-[7px] text-[.86rem] font-semibold text-bl-muted transition-colors duration-150 hover:text-bl-ink aria-pressed:bg-white aria-pressed:text-bl-ink aria-pressed:shadow-[0_1px_2px_rgba(23,32,51,.12),0_0_0_1px_var(--color-bl-line)] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" type="button" data-filter="open" aria-pressed="false">Due</button><button class="cursor-pointer rounded-[9px] px-[13px] py-[7px] text-[.86rem] font-semibold text-bl-muted transition-colors duration-150 hover:text-bl-ink aria-pressed:bg-white aria-pressed:text-bl-ink aria-pressed:shadow-[0_1px_2px_rgba(23,32,51,.12),0_0_0_1px_var(--color-bl-line)] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" type="button" data-filter="overdue" aria-pressed="false">Overdue</button><button class="cursor-pointer rounded-[9px] px-[13px] py-[7px] text-[.86rem] font-semibold text-bl-muted transition-colors duration-150 hover:text-bl-ink aria-pressed:bg-white aria-pressed:text-bl-ink aria-pressed:shadow-[0_1px_2px_rgba(23,32,51,.12),0_0_0_1px_var(--color-bl-line)] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" type="button" data-filter="paid" aria-pressed="false">Paid</button><button class="cursor-pointer rounded-[9px] px-[13px] py-[7px] text-[.86rem] font-semibold text-bl-muted transition-colors duration-150 hover:text-bl-ink aria-pressed:bg-white aria-pressed:text-bl-ink aria-pressed:shadow-[0_1px_2px_rgba(23,32,51,.12),0_0_0_1px_var(--color-bl-line)] motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" type="button" data-filter="draft" aria-pressed="false">Draft</button></div>
    <div class="relative flex-[0_1_260px] max-[480px]:flex-[1_1_100%]"><label class="sr-only" for="bl-search">Search invoices by client or number</label>
      <svg class="pointer-events-none absolute top-1/2 left-[11px] -translate-y-1/2 text-bl-muted" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="6.5"/><path d="M16 16l4.5 4.5"/></svg>
      <input class="min-h-10 w-full rounded-[10px] border border-bl-edge bg-white py-2 pr-3 pl-[34px] placeholder:text-[#626b7c] focus:border-bl-accent focus:shadow-[0_0_0_3px_rgba(29,78,216,.2)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" id="bl-search" type="search" placeholder="Search client or number" data-search autocomplete="off"></div>
  </div>
  <div class="relative overflow-x-auto rounded-[14px] border border-bl-line focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" role="region" aria-labelledby="bl-caption" tabindex="0">
    <table class="w-full min-w-[720px] border-collapse tabular-nums">
      <caption class="sr-only" id="bl-caption">Invoices, newest first</caption>
      <thead><tr class="[&>th]:border-b [&>th]:border-bl-line [&>th]:bg-bl-soft [&>th]:px-3.5 [&>th]:py-[11px] [&>th]:text-left [&>th]:text-[.75rem] [&>th]:font-semibold [&>th]:tracking-[.06em] [&>th]:whitespace-nowrap [&>th]:text-bl-muted [&>th]:uppercase"><th scope="col">Invoice</th><th scope="col">Client</th><th scope="col">Issued</th><th scope="col">Due</th><th scope="col" class="text-right!">Amount</th><th scope="col">Status</th><th scope="col" class="text-right!"><span class="sr-only">Actions</span></th></tr></thead>
      <tbody>
        <tr data-status="draft" data-amount="560000" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2042</th><td class="">Fieldstone Architects</td><td class=" text-bl-muted">—</td><td class=" text-bl-muted">—</td><td class=" text-right!">$5,600.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#cfd4dc] bg-[#f2f4f7] text-[#475467]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20h4L19 9l-4-4L4 16z"/><path d="M13.5 6.5l4 4"/></svg>Draft</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2042">Edit<span class="sr-only"> INV-2042</span></a></td></tr>
        <tr data-status="open" data-amount="425000" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2041</th><td class="">Harbor & Vine Winery</td><td class=" text-bl-muted">2 Oct 2026</td><td class=" text-bl-muted">1 Nov 2026</td><td class=" text-right!">$4,250.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#b6c8f5] bg-[#eff4ff] text-[#1e40af]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></svg>Due</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2041">View<span class="sr-only"> INV-2041</span></a></td></tr>
        <tr data-status="paid" data-amount="118000" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2040</th><td class="">Copperleaf Dental</td><td class=" text-bl-muted">28 Sep 2026</td><td class=" text-bl-muted">28 Oct 2026</td><td class=" text-right!">$1,180.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#a6dfbb] bg-[#ecfdf3] text-[#166534]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2040">View<span class="sr-only"> INV-2040</span></a></td></tr>
        <tr data-status="overdue" data-amount="264000" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2039</th><td class="">Northgate Fitness</td><td class=" text-bl-muted">15 Sep 2026</td><td class=" text-bl-muted">15 Oct 2026</td><td class=" text-right!">$2,640.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#f3b8b2] bg-[#fef3f2] text-[#b42318]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2039">View<span class="sr-only"> INV-2039</span></a></td></tr>
        <tr data-status="paid" data-amount="39500" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2038</th><td class="">Bluebell Florist</td><td class=" text-bl-muted">12 Sep 2026</td><td class=" text-bl-muted">12 Oct 2026</td><td class=" text-right!">$395.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#a6dfbb] bg-[#ecfdf3] text-[#166534]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2038">View<span class="sr-only"> INV-2038</span></a></td></tr>
        <tr data-status="overdue" data-amount="387050" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2037</th><td class="">Atlas Removals</td><td class=" text-bl-muted">3 Sep 2026</td><td class=" text-bl-muted">3 Oct 2026</td><td class=" text-right!">$3,870.50</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#f3b8b2] bg-[#fef3f2] text-[#b42318]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2037">View<span class="sr-only"> INV-2037</span></a></td></tr>
        <tr data-status="paid" data-amount="64000" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2036</th><td class="">Quayside Books</td><td class=" text-bl-muted">1 Sep 2026</td><td class=" text-bl-muted">1 Oct 2026</td><td class=" text-right!">$640.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#a6dfbb] bg-[#ecfdf3] text-[#166534]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2036">View<span class="sr-only"> INV-2036</span></a></td></tr>
        <tr data-status="overdue" data-amount="121500" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2035</th><td class="">Saltmarsh Surf School</td><td class=" text-bl-muted">20 Aug 2026</td><td class=" text-bl-muted">19 Sep 2026</td><td class=" text-right!">$1,215.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#f3b8b2] bg-[#fef3f2] text-[#b42318]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2035">View<span class="sr-only"> INV-2035</span></a></td></tr>
        <tr data-status="paid" data-amount="89000" class="hover:bg-[#fafbfd] [&>*]:border-b [&>*]:border-bl-line [&>*]:px-3.5 [&>*]:py-[13px] [&>*]:text-left [&>*]:whitespace-nowrap"><th scope="row" class="font-bold">INV-2034</th><td class="">Redkite Coffee</td><td class=" text-bl-muted">18 Aug 2026</td><td class=" text-bl-muted">17 Sep 2026</td><td class=" text-right!">$890.00</td><td class=""><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#a6dfbb] bg-[#ecfdf3] text-[#166534]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></td><td class=" text-right!"><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2034">View<span class="sr-only"> INV-2034</span></a></td></tr>
        <tr data-empty hidden><td colspan="7" class="p-7 text-center text-bl-muted">No invoices match this filter.</td></tr>
      </tbody>
      <tfoot><tr class="[&>*]:px-3.5 [&>*]:py-3 [&>*]:text-left [&>*]:font-bold [&>th]:font-semibold [&>th]:text-bl-muted"><th scope="row" colspan="4" data-count>Showing 9 of 9</th><td class="text-right!" data-sum>$20,680.50</td><td colspan="2"></td></tr></tfoot>
    </table>
  </div>
  <p class="sr-only" role="status" data-status-msg></p>
</section>
</div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#525c6e] uppercase">Recent invoices card for a sidebar</span>
<section class="rounded-[18px] bg-white p-7 text-[14px] leading-[1.45] text-bl-ink shadow-[0_1px_2px_rgba(23,32,51,.06),0_24px_48px_-30px_rgba(23,32,51,.35)] max-[480px]:px-4 max-[480px]:py-5 max-w-[420px] p-[22px]!" aria-labelledby="bl2-title">
  <div class="mb-2 flex items-baseline justify-between"><h2 class="text-[1.1rem] font-bold" id="bl2-title">Recent invoices</h2><a class="font-semibold text-bl-accent hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#all-invoices">View all<span class="sr-only"> invoices</span></a></div>
  <ul class="">
      <li class="flex justify-between gap-3 border-t border-bl-line py-3"><div class="min-w-0"><a class="font-semibold text-bl-ink hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2041">Harbor & Vine Winery</a><p class="text-[.8rem] text-bl-muted">INV-2041 · Due 1 Nov 2026</p></div><div class="grid flex-none justify-items-end gap-1"><p class="font-bold tabular-nums">$4,250.00</p><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#b6c8f5] bg-[#eff4ff] text-[#1e40af]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></svg>Due</span></div></li>
      <li class="flex justify-between gap-3 border-t border-bl-line py-3"><div class="min-w-0"><a class="font-semibold text-bl-ink hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2040">Copperleaf Dental</a><p class="text-[.8rem] text-bl-muted">INV-2040 · Paid</p></div><div class="grid flex-none justify-items-end gap-1"><p class="font-bold tabular-nums">$1,180.00</p><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#a6dfbb] bg-[#ecfdf3] text-[#166534]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></div></li>
      <li class="flex justify-between gap-3 border-t border-bl-line py-3"><div class="min-w-0"><a class="font-semibold text-bl-ink hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2039">Northgate Fitness</a><p class="text-[.8rem] text-bl-muted">INV-2039 · Was due 15 Oct 2026</p></div><div class="grid flex-none justify-items-end gap-1"><p class="font-bold tabular-nums">$2,640.00</p><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#f3b8b2] bg-[#fef3f2] text-[#b42318]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></div></li>
      <li class="flex justify-between gap-3 border-t border-bl-line py-3"><div class="min-w-0"><a class="font-semibold text-bl-ink hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2038">Bluebell Florist</a><p class="text-[.8rem] text-bl-muted">INV-2038 · Paid</p></div><div class="grid flex-none justify-items-end gap-1"><p class="font-bold tabular-nums">$395.00</p><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#a6dfbb] bg-[#ecfdf3] text-[#166534]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>Paid</span></div></li>
      <li class="flex justify-between gap-3 border-t border-bl-line py-3"><div class="min-w-0"><a class="font-semibold text-bl-ink hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-bl-accent" href="#inv-2037">Atlas Removals</a><p class="text-[.8rem] text-bl-muted">INV-2037 · Was due 3 Oct 2026</p></div><div class="grid flex-none justify-items-end gap-1"><p class="font-bold tabular-nums">$3,870.50</p><span class="inline-flex items-center gap-[5px] rounded-full border py-[3px] pr-2.5 pl-2 text-[.78rem] font-bold border-[#f3b8b2] bg-[#fef3f2] text-[#b42318]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l9.5 16.5h-19z"/><path d="M12 10v4.5M12 17.5v.01"/></svg>Overdue</span></div></li>
      </ul>
</section>
</div>
CSS
@theme {
  --color-bl-accent: #1d4ed8;
  --color-bl-accent-dark: #1e40af;
  --color-bl-ink: #172033;
  --color-bl-muted: #525c6e;
  --color-bl-line: #e2e6ee;
  --color-bl-edge: #7d8698;
  --color-bl-soft: #f5f7fb;
}
JavaScript
// Status filter and search for the invoice table. Each row carries data-status and data-amount (in cents);
// the footer shows how many rows are visible and their total, and the status line is announced politely.
document.querySelectorAll('[data-invoices]').forEach(function (root) {
  var rows = Array.prototype.slice.call(root.querySelectorAll('tbody tr[data-status]'));
  var buttons = root.querySelectorAll('[data-filter]');
  var search = root.querySelector('[data-search]');
  var toolbar = root.querySelector('[data-toolbar]');
  var count = root.querySelector('[data-count]');
  var sum = root.querySelector('[data-sum]');
  var empty = root.querySelector('[data-empty]');
  var status = root.querySelector('[data-status-msg]');
  var fmt = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
  var filter = 'all', timer;
  if (toolbar) toolbar.hidden = false;

  function apply(announce) {
    var q = search ? search.value.trim().toLowerCase() : '', shown = 0, total = 0;
    rows.forEach(function (row) {
      var ok = (filter === 'all' || row.dataset.status === filter) && (!q || row.textContent.toLowerCase().indexOf(q) > -1);
      row.hidden = !ok;
      if (ok) { shown += 1; total += +row.dataset.amount; }
    });
    var label = shown + (shown === 1 ? ' invoice' : ' invoices');
    count.textContent = 'Showing ' + shown + ' of ' + rows.length;
    sum.textContent = fmt.format(total / 100);
    if (empty) empty.hidden = shown > 0;
    if (announce && status) status.textContent = label + ', ' + fmt.format(total / 100) + '.';
  }
  buttons.forEach(function (btn) {
    btn.addEventListener('click', function () {
      filter = btn.dataset.filter;
      buttons.forEach(function (b) { b.setAttribute('aria-pressed', String(b === btn)); });
      apply(true);
    });
  });
  if (search) search.addEventListener('input', function () { clearTimeout(timer); apply(false); timer = setTimeout(function () { apply(true); }, 500); });
  apply(false);
});

About this set

A billing dashboard and a sidebar card for keeping track of invoices. Billing dashboard with status filters and search opens with four summary tiles for outstanding, overdue, recently paid and draft totals, then a toolbar of status filters (All, Due, Overdue, Paid, Draft) and a search box, and a table of nine invoices with number, client, issued and due dates, amount, a status pill and a View or Edit link. The table footer shows how many invoices are visible and what they add up to. Recent invoices card for a sidebar lists the latest five with client, number, due date, amount and status. Every status pill pairs a word with its own icon (a tick, a clock, a warning triangle, a pencil) as well as a colour, so the status never depends on colour alone. A few lines of vanilla JavaScript filter the rows by status and text, update the count and total, and announce the result; without JavaScript the toolbar stays hidden and the full table shows. On narrow screens the table scrolls sideways inside a labelled region.

What’s included

  • Summary tiles for outstanding, overdue, paid and draft totals
  • Status filter buttons with aria-pressed and a search box
  • Live count and total of the visible invoices in the table footer
  • Status pills with text and icon: Paid, Due, Overdue, Draft
  • Recent invoices card for sidebars, no JavaScript

Accessibility

Filters are a labelled group of toggle buttons that expose aria-pressed, the search field has a label, and results are announced in a polite status region. The table has a caption, scoped headers, and View links that include the invoice number for screen readers; on small screens it sits in a focusable, labelled scroll region. Status never relies on colour alone, every control shows a focus outline, and transitions stop under prefers-reduced-motion.

Customise it

Change --bl-accent, --bl-ink, --bl-muted and the .bl-pill--* colours on .bl. The script uses data-invoices, data-status, data-amount (in cents), data-filter, data-search, data-count and data-sum. Bootstrap restyles .btn-group, .badge and .table-hover through the same variables; in Tailwind edit the bl-* colours in @theme.