Skip to content

Data displayTable

Table

A semantic HTML table. Numeric columns use tabular-nums. Headers are uppercase tracked labels.

Native <table>Sticky header on long tablesRow hover state

Demo

Default
TokenHexUse
--foreground#1A1816Body text, primary
--muted-foreground#6F6860Helper, caption
--border#DDD7CEDefault borders

Compact

Compact
TokenHex
--foreground#1A1816
--muted-foreground#6F6860

Anatomy

  • 1 px --line-strong outer border, 4 px radius
  • Header: --surface-elevated background, 0.6875 rem uppercase 0.14 em tracking, --muted-foreground
  • Cell padding: 12 px / 16 px at default, 6 px / 16 px at compact
  • Row border: 1 px --line-subtle between rows
  • Hover: --surface-inset at 50% opacity
  • Numeric cells use font-variant-numeric: tabular-nums

Implementation

table.tsx
import { type ReactNode } from "react"
import { cn } from "@/lib/utils"

export interface DocTableColumn {
  key: string
  label: string
  width?: string
}

interface DocTableProps {
  columns: DocTableColumn[]
  rows: { id: string; cells: ReactNode[] }[]
  compact?: boolean
}

export default function DocTable({ columns, rows, compact }: DocTableProps) {
  return (
    <div className="ds-table-wrap">
      <table className={cn("ds-table", compact && "ds-table--compact")}>
        <thead>
          <tr>
            {columns.map((col) => (
              <th key={col.key} style={col.width ? { width: col.width } : undefined}>
                {col.label}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((row) => (
            <tr key={row.id}>
              {row.cells.map((cell, i) => (
                <td key={i}>{cell}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

Props

PropTypeDefaultDescription
columnsDocTableColumn[]NoneRequired: column definitions
rows{ id: string; cells: ReactNode[] }[]NoneRequired: row data
compactbooleanfalseReduce vertical padding