Novus Technologies Novus Technologies design kit v0.9.0
Menu

Data Display

Table

Data-dense table: single-line cells in a scroll container, right-aligned numerals, end-aligned actions.

.table · .tablewrap · .cell--wrap · .cell--actions · .cell-stack

ReferenceMerchantProductAmount (USD)StatusSubmittedActions
TXN-241099Hillcrest Grocers Makatinovapay151.17 Status · Settled27 Aug 2026, 18:31
TXN-241073Riverside Fuel Station 12novastore401.87 Status · Pending27 Aug 2026, 17:57
TXN-240981Harbourfront Pharmacynovabank96.40 Status · Failed27 Aug 2026, 15:12
Data table in a scroll container: every cell on one line
<div class="card card--flush">
  <div class="tablewrap">
    <table class="table">
      <thead><tr><th>Reference</th><th>Merchant</th><th>Product</th><th class="num">Amount (USD)</th><th>Status</th><th>Submitted</th><th class="cell--actions">Actions</th></tr></thead>
      <tbody>
        <tr><td><code>TXN-241099</code></td><td>Hillcrest Grocers Makati</td><td>novapay</td><td class="num">151.17</td><td><span class="badge badge--success"><span class="badge__dot"></span> Status · Settled</span></td><td>27 Aug 2026, 18:31</td><td class="cell--actions"><button class="btn btn--ghost btn--sm">Detail</button></td></tr>
        <tr><td><code>TXN-241073</code></td><td>Riverside Fuel Station 12</td><td>novastore</td><td class="num">401.87</td><td><span class="badge badge--warning"><span class="badge__dot"></span> Status · Pending</span></td><td>27 Aug 2026, 17:57</td><td class="cell--actions"><button class="btn btn--ghost btn--sm">Detail</button></td></tr>
        <tr><td><code>TXN-240981</code></td><td>Harbourfront Pharmacy</td><td>novabank</td><td class="num">96.40</td><td><span class="badge badge--danger"><span class="badge__dot"></span> Status · Failed</span></td><td>27 Aug 2026, 15:12</td><td class="cell--actions"><button class="btn btn--ghost btn--sm">Detail</button></td></tr>
      </tbody>
    </table>
  </div>
</div>
HolderTerminalNote
UnclaimedCredit analyst
TRM-0128Two failed settlements in the last hour on the same terminal; review the device before the next batch window.
ops.adminOperations
TRM-0177Gateway certificate renewal scheduled.
Two-line cells and a wrapping note column
<div class="tablewrap">
  <table class="table">
    <thead><tr><th>Holder</th><th>Terminal</th><th>Note</th></tr></thead>
    <tbody>
      <tr><td><div class="cell-stack"><span>Unclaimed</span><span class="cell-stack__meta">Credit analyst</span></div></td><td><code>TRM-0128</code></td><td class="cell--wrap">Two failed settlements in the last hour on the same terminal; review the device before the next batch window.</td></tr>
      <tr><td><div class="cell-stack"><span>ops.admin</span><span class="cell-stack__meta">Operations</span></div></td><td><code>TRM-0177</code></td><td class="cell--wrap">Gateway certificate renewal scheduled.</td></tr>
    </tbody>
  </table>
</div>

Usage

  • Put every data table in a .tablewrap: cells stay on one line and the table scrolls sideways inside its container instead of squeezing columns, so identifiers, names, chips, dates, and amounts never break across lines. The page itself never scrolls sideways.
  • Free-text columns opt back into wrapping with .cell--wrap, which keeps a readable minimum width.
  • A second fact in a cell goes in a .cell-stack: two single-line lines, the second one muted.
  • Numeric columns take class="num" on the header and the cells (right-aligned, tabular numerals); row actions take .cell--actions, aligned to the end.
  • Header cells sit on the subtle tint; rows highlight on hover for scanning. See Alignment and content fit.

Popovers and menus in a table

The scroll wrap is a containing block, so anything absolutely positioned inside it is clipped by it. That is deliberate: it keeps visually hidden text from extending the page sideways on a phone. It also means a row menu, popover or tooltip must render outside the wrap rather than inside the cell it belongs to.

CSS

These rules ship in the console pattern layer, admin-kits/shared/novus-admin.css, which this site and every Admin Kit flavor load after tokens.css. Copy the whole layer, or only the sections below; every value is a token.

@pattern content-fit
/* One short value, one line. Tables scroll inside .tablewrap instead of
   squeezing; free text opts back into wrapping; fixed slots truncate. */
.badge, .filterchip, .quickchip, .crumbs li, .paginator__label, .listfooter__range, .nowrap { white-space: nowrap; }
.truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Positioned so the wrap is the containing block for its own absolutely positioned
   descendants. Without this, a .sr-only span inside a horizontally scrolled table
   resolves against the initial containing block, escapes this clip, and extends the
   document's scroll width: the page scrolls sideways on a phone while the table
   looks correctly contained. A popover inside a scrolling table must therefore be
   rendered outside the wrap, because it is now clipped by it. */
.tablewrap { position: relative; overflow-x: auto; overscroll-behavior-x: contain; }
.tablewrap table th, .tablewrap table td { white-space: nowrap; vertical-align: middle; }
.tablewrap table .cell--wrap { white-space: normal; min-width: 16rem; }
.table th.num, .table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.table th.cell--actions, .table td.cell--actions { text-align: right; width: 1%; }
.cell--actions .btn + .btn { margin-inline-start: var(--space-2); }
.cell-stack { display: flex; flex-direction: column; gap: calc(var(--space-1) / 2); }
.cell-stack__meta { font-size: var(--text-xs); line-height: var(--lh-xs); color: var(--text-secondary); }
/* Portal text uses the width of its row: the kit's reading measure is for
   prose, so console screens reset it. A measure is opted into explicitly
   (constitution 1.12.0, Principle IV). */
.adminmain p, .adminmain li, .authcard p, .settings p, .signedout p, .chartcard p { max-width: none; }
.measure { max-width: 68ch; }