Open demo

CSS code

HTML
<h2 class="mt-title" id="mt-title">Holdings</h2>
<p class="mt-sub">The quietest possible table: hairlines only, generous spacing, tabular numerals.</p>
<table class="mt" aria-labelledby="mt-title">
  <thead><tr><th scope="col">Asset</th><th scope="col">Position</th><th scope="col">Value</th><th scope="col">24h</th></tr></thead>
  <tbody>
    <tr><th scope="row">Index Fund<span>VWCE · Accumulating</span></th><td class="num">148.2 units</td><td class="num">$18,940</td><td class="num up">+0.8%</td></tr>
    <tr><th scope="row">Treasury Bonds<span>10-year ladder</span></th><td class="num">—</td><td class="num">$12,500</td><td class="num up">+0.1%</td></tr>
    <tr><th scope="row">Tech Basket<span>Direct holdings · 6 names</span></th><td class="num">88 shares</td><td class="num">$9,215</td><td class="num down">−1.4%</td></tr>
    <tr><th scope="row">Cash<span>EUR + USD</span></th><td class="num">—</td><td class="num">$4,060</td><td class="num">0.0%</td></tr>
    <tr><th scope="row">Commodities<span>Gold ETC</span></th><td class="num">21 units</td><td class="num">$3,480</td><td class="num up">+0.5%</td></tr>
  </tbody>
</table>
CSS
/* Minimal table: hairlines between rows only, generous spacing and tabular numerals. */
.mt-title{font-size:1.15rem;font-weight:700;letter-spacing:-.01em;margin:0 0 4px}
.mt-sub{color:#6b717d;font-size:.87rem;margin:0 0 26px}
.mt{width:100%;border-collapse:collapse;font-size:.92rem}
.mt th,.mt td{text-align:left}
.mt thead th{font-weight:600;font-size:.8rem;color:#6b717d;padding:0 0 12px}
.mt tbody th,.mt td{padding:15px 0;border-top:1px solid #ebedf0}
.mt th:last-child,.mt td:last-child{text-align:right}
.mt tbody th{font-weight:600}
.mt tbody th span{display:block;font-weight:400;font-size:.8rem;color:#6b717d;margin-top:2px}
.mt .num{font-variant-numeric:tabular-nums;color:#3c4048}
.mt .up{color:#0b7a3c}
.mt .down{color:#c22f2f}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<h2 class="mt-title" id="mt-title">Holdings</h2>
<p class="mt-sub">The quietest possible table: hairlines only, generous spacing, tabular numerals.</p>
<table class="table mt align-middle mb-0" aria-labelledby="mt-title">
  <thead><tr><th scope="col">Asset</th><th scope="col">Position</th><th scope="col">Value</th><th scope="col" class="text-end">24h</th></tr></thead>
  <tbody>
    <tr><th scope="row">Index Fund<span>VWCE · Accumulating</span></th><td class="num">148.2 units</td><td class="num">$18,940</td><td class="num up text-end">+0.8%</td></tr>
    <tr><th scope="row">Treasury Bonds<span>10-year ladder</span></th><td class="num">—</td><td class="num">$12,500</td><td class="num up text-end">+0.1%</td></tr>
    <tr><th scope="row">Tech Basket<span>Direct holdings · 6 names</span></th><td class="num">88 shares</td><td class="num">$9,215</td><td class="num down text-end">−1.4%</td></tr>
    <tr><th scope="row">Cash<span>EUR + USD</span></th><td class="num">—</td><td class="num">$4,060</td><td class="num text-end">0.0%</td></tr>
    <tr><th scope="row">Commodities<span>Gold ETC</span></th><td class="num">21 units</td><td class="num">$3,480</td><td class="num up text-end">+0.5%</td></tr>
  </tbody>
</table>
CSS
/* Bootstrap .table reduced to hairlines: the row borders move from the bottom of each cell to the top. */
.mt-title{font-size:1.15rem;font-weight:700;letter-spacing:-.01em;line-height:normal;margin:0 0 4px}
.mt-sub{color:#6b717d;font-size:.87rem;margin:0 0 26px}
.mt{--bs-table-color:#16181c;--bs-table-bg:transparent;--bs-table-border-color:#ebedf0;font-size:.92rem}
.mt>:not(caption)>*>*{padding:15px 0;border-bottom-width:0}
.mt>tbody>tr>*{border-top:1px solid var(--bs-table-border-color)}
.mt>thead>tr>th{padding:0 0 12px;font-weight:600;font-size:.8rem;--bs-table-color:#6b717d}
.mt tbody th{font-weight:600}
.mt tbody th span{display:block;font-weight:400;font-size:.8rem;color:#6b717d;margin-top:2px}
.mt .num{font-variant-numeric:tabular-nums;--bs-table-color:#3c4048}
.mt .up{--bs-table-color:#0b7a3c}
.mt .down{--bs-table-color:#c22f2f}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<h2 id="mt-title" class="mb-1 text-[1.15rem] font-bold tracking-[-.01em]">Holdings</h2>
<p class="mb-[26px] text-[.87rem] text-[#6b717d]">The quietest possible table: hairlines only, generous spacing, tabular numerals.</p>
<table aria-labelledby="mt-title" class="w-full border-collapse text-[.92rem] [&_th]:text-left [&_tr>*:last-child]:text-right">
  <thead class="text-[.8rem] text-[#6b717d] [&_th]:pb-3 [&_th]:font-semibold"><tr><th scope="col">Asset</th><th scope="col">Position</th><th scope="col">Value</th><th scope="col">24h</th></tr></thead>
  <tbody class="[&_td]:border-t [&_td]:border-[#ebedf0] [&_td]:py-[15px] [&_td]:text-[#3c4048] [&_td]:tabular-nums [&_th]:border-t [&_th]:border-[#ebedf0] [&_th]:py-[15px] [&_th]:font-semibold [&_span]:mt-0.5 [&_span]:block [&_span]:text-[.8rem] [&_span]:font-normal [&_span]:text-[#6b717d]">
    <tr><th scope="row">Index Fund<span>VWCE · Accumulating</span></th><td>148.2 units</td><td>$18,940</td><td class="text-[#0b7a3c]!">+0.8%</td></tr>
    <tr><th scope="row">Treasury Bonds<span>10-year ladder</span></th><td>—</td><td>$12,500</td><td class="text-[#0b7a3c]!">+0.1%</td></tr>
    <tr><th scope="row">Tech Basket<span>Direct holdings · 6 names</span></th><td>88 shares</td><td>$9,215</td><td class="text-[#c22f2f]!">−1.4%</td></tr>
    <tr><th scope="row">Cash<span>EUR + USD</span></th><td>—</td><td>$4,060</td><td>0.0%</td></tr>
    <tr><th scope="row">Commodities<span>Gold ETC</span></th><td>21 units</td><td>$3,480</td><td class="text-[#0b7a3c]!">+0.5%</td></tr>
  </tbody>
</table>

About this set

The quietest table in the pack: no backgrounds, no header fill and no vertical lines, only a one pixel hairline above each row, generous 15 pixel row padding and tabular numerals. The example is a portfolio of holdings with the asset name as a row header and a smaller grey subtitle underneath, then position, value and a 24 hour change that is green, red or neutral. The last column is right-aligned so the percentages line up. Use it in editorial layouts, personal finance pages, settings summaries or anywhere a boxed data grid would feel heavy, and for tables with only a handful of columns; with many columns the missing vertical lines make scanning harder. It fits a 375 pixel phone screen without scrolling, so it needs no scroll wrapper. There is no JavaScript and no interactive element. The Bootstrap version keeps .table but moves the border from the bottom of each cell to the top and removes the header border through variables and two rules, and the Tailwind version draws the hairlines with border-t utilities applied from the tbody.

What’s included

  • Hairline rules only, no fills or vertical lines
  • Tabular numerals with a right-aligned change column
  • Row headers with a secondary subtitle
  • Green and red changes at 4.5:1 contrast or better
  • Fits a 375px screen without horizontal scroll

Accessibility

The table is labelled by its heading through aria-labelledby, with scope on column and row headers. Grey header and subtitle text is #6b717d (4.9:1) and the change colours meet 4.5:1. Nothing in the table is interactive, so there is no focus handling.

Customise it

Edit the .mt rules: hairline #ebedf0, muted text #6b717d, gain #0b7a3c, loss #c22f2f, row padding 15px. In Bootstrap the same values sit in --bs-table-border-color and --bs-table-color; in Tailwind change border-[#ebedf0] and the text- utilities.