Skip to content

Leaderboard Table

Ranked list with ink header, colored podium squares for the top 3, proportional background bars behind each row, rank-change chips (▲/▼) and big tabular values. Sorts by value automatically.

brutalist/ui/leaderboard-table
Open ↗

Source

import { cn } from "@/lib/utils";

export interface LeaderboardEntry {
  name: string;
  detail?: string;
  value: number;
  /** Position change since last period (+ up, − down). */
  change?: number;
}

export interface LeaderboardTableProps {
  title: string;
  valueLabel?: string;
  entries: LeaderboardEntry[];
  format?: (value: number) => string;
  className?: string;
}

const PODIUM = ["bg-da-primary text-da-primary-fg", "bg-da-accent text-da-accent-fg", "bg-da-secondary text-da-secondary-fg"];

export function LeaderboardTable({ title, valueLabel = "Score", entries, format = (v) => v.toLocaleString("en-US"), className }: LeaderboardTableProps) {
  const sorted = [...entries].sort((a, b) => b.value - a.value);
  const max = sorted[0]?.value ?? 1;

  return (
    <div className={cn("da-stroke bg-da-surface text-da-surface-fg shadow-da-md", className)}>
      <div className="da-stroke-b flex items-center justify-between bg-da-fg px-4 py-3 text-da-bg">
        <h3 className="font-da-display text-lg tracking-da-display uppercase">{title}</h3>
        <span className="font-da-mono text-[11px] font-bold tracking-da-label uppercase">{valueLabel}</span>
      </div>
      <ol>
        {sorted.map((e, i) => (
          <li key={e.name} className={cn("relative flex items-center gap-4 px-4 py-3", i > 0 && "da-stroke-t")}>
            <span aria-hidden className="absolute inset-y-0 left-0 bg-da-muted" style={{ width: `${(e.value / max) * 100}%` }} />
            <span className={cn("da-stroke relative grid size-9 shrink-0 place-items-center font-da-display", PODIUM[i] ?? "bg-da-surface")}>
              {i + 1}
              <span className="sr-only">. place</span>
            </span>
            <span className="relative min-w-0 flex-1">
              <span className="block truncate font-bold">{e.name}</span>
              {e.detail && <span className="block truncate font-da-mono text-xs text-da-muted-fg">{e.detail}</span>}
            </span>
            {e.change !== undefined && e.change !== 0 && (
              <span className={cn("da-stroke relative px-1 font-da-mono text-[11px] font-bold", e.change > 0 ? "bg-da-success text-da-success-fg" : "bg-da-danger text-da-danger-fg")}>
                {e.change > 0 ? `▲${e.change}` : `▼${Math.abs(e.change)}`}
                <span className="sr-only">{e.change > 0 ? " places up" : " places down"}</span>
              </span>
            )}
            <span className="relative font-da-display text-xl tabular-nums">{format(e.value)}</span>
          </li>
        ))}
      </ol>
    </div>
  );
}

export default LeaderboardTable;

modules/brutalist/ui/leaderboard-table/index.tsx

Props

PropTypeDefaultDescription
title*string—Header title (h3).
valueLabelstring"Score"Label of the value column.
entries*LeaderboardEntry[]—{ name, detail?, value, change? }[].
format(value: number) => string—Value formatter (default en-US thousands).
classNamestring—Classes on the wrapper.

Other table variants in Brutalist

Table in other art directions

Action Items Table

Action items table with Open / Done / All filter pills and counts, gradient checkboxes that strike tasks through, owner, due chip (overdue in red) and source meeting; empty state.

GlassTable

Data Table

Frosted table panel with title, description, pill search field and actions slot; rows are separated translucent rounded strips that brighten on hover. Typed generic columns, sorting, mobile hiding, empty state.

GlassTable

Meetings Table

Recent meetings glass table: title with gradient video icon and platform, date, mono duration, participant avatar stack and a recap status pill (ready, processing, private).

GlassTable

Usage Table

Team usage glass table: member, inline gradient bar of recorded hours relative to the top member, meetings count and hours saved, with a tinted totals row.

GlassTable

Data Table

Typed generic table with hairline rows, sortable headers, optional row selection (select-all with indeterminate state) and a floating bulk-action bar. Custom cells, mobile column hiding, empty state.

MinimalTable

Grouped Table

Services table grouped by team: collapsible tinted group rows with service count and alert subtotal, then rows with status dot, mono service name, owner, alerts and MTTA.

MinimalTable

Paginated Table

Audit-log table with client-side pagination: page-size select, “1–10 of 47” range, numbered pages with ellipsis and prev/next; mono timestamps and IPs, horizontal scroll on mobile.

MinimalTable

Uptime Table

Status-page uptime table: one row per service with 30 daily bars colored by threshold (≥ 99.99 %, ≥ 99 %, below), a current-status dot, the 30-day average and a legend.

MinimalTable

Changelog Table

Release log laid out as a table: mono version + ISO date column, a square type tag (New in signal color, Improved outlined, Fixed gray) and dash-listed notes; hairline rows.

Mono CleanTable

Data Table

Analytics table in pure typography: mono headers that sort (↑/↓ glyph, aria-sort), hairline rows, tabular numbers, inline hairline bars for share of views, and an ink total row.

Mono CleanTable

Projects Table

Studio project index (the classic portfolio list): large titles with client, discipline and year in mono columns; each row is one link that inverts to ink on hover with an ↗.

Mono CleanTable

Sites Table

Sites dashboard table: name + domain link, dot status in mono, template, updated time and a “…” Radix dropdown (open, duplicate, archive); hairline rows.

Mono CleanTable

Approvals Table

Bill approval queue: vendor + requester, category, mono amount and inline Approve / Reject buttons that turn the row into a decided state (with Undo); pending count in the header.

Neo CorporateTable

Data Table

Customer data table: sortable headers (aria-sort), row checkboxes with select-all (indeterminate), bulk-action bar when rows are selected, mono amounts and pagination.

Neo CorporateTable

Invoice Table

Receivables table with status pills, days-late aging text, mono amounts, a totals footer and a per-row Radix dropdown (view, send reminder, duplicate, void).

Neo CorporateTable

Ledger Table

General-ledger table grouped by date: journal ref and memo, GL account, debit/credit columns in mono, credits indented, and balanced totals row with a “Balanced” check.

Neo CorporateTable

Actions Table

Reduction plan table: round checkboxes mark actions done (row softens), owner and due date, mono savings, and a progress header showing tonnes secured toward the target.

Organic SoftTable

Emissions Table

Emissions by category: rounded cream table with scope leaf chips, inline sage share bars behind the tonnes, mono figures, colored year-over-year change and a total row.

Organic SoftTable

Monthly Table

Month × scope heat table: each cell tinted by intensity along a sand→sage→forest scale with mono values; row totals and a legend; readable without color.

Organic SoftTable

Supplier Table

Supplier engagement table: filter pills by status, arch avatars, share of footprint, status pill and 3-dot data quality meter, with a per-row “Nudge” pill that turns into “Sent”.

Organic SoftTable

Activity Table

Activity log table: kind icon in a pastel circle, emoji avatar and sentence (“Ana completed …”), board chip and relative time; rows highlight softly on hover.

Soft FlatTable

Simple Table

Plain friendly data table in a rounded white card: soft header well, roomy rows, gentle zebra and right-aligned numbers; generic columns and rows props.

Soft FlatTable

Task Table

“My tasks” table where each row is a soft rounded strip: round done checkbox, title (struck when done), pastel board chip, owner initial avatar and due chip (red when overdue).

Soft FlatTable

Workload Table

Team workload heat table: a row per person (emoji + name), one rounded cell per weekday tinted mint → butter → peach by number of tasks, with a legend.

Soft FlatTable