Efniv0.1

Components

Data table

Table + @tanstack/react-table. Sorting, filtering, and pagination out of the box. Define columns once, pass rows, get a sortable, paged table.

When to usewhen the surface is fundamentally rows — anything with more than ~30 items where the operator wants to sort or scan.

Import

import { DataTable, SortableHeader } from "@ravnhq/efni/data-table"
import type { ColumnDef } from "@tanstack/react-table"

Mission ops table

Status
MB-4472
NANora Adell
in flight
x
62%
MB-4468
RCRavi Chandra
queued
x
0%
MB-4451
JPJules Park
completed
x
100%
MB-4432
IMIris Molinari
aborted
x
34%
MB-4421
KOKito Odum
in flight
x
88%
MB-4415
SVSena Voss
completed
x
100%
Page 1 of 2
const columns: ColumnDef<Mission>[] = [
  {
    accessorKey: "id",
    header: ({ column }) => <SortableHeader column={column}>ID</SortableHeader>,
    cell: ({ row }) => <span className="font-mono">{row.getValue("id")}</span>,
  },
  { accessorKey: "operator", header: "Operator" },
  { accessorKey: "status", header: "Status" },
  {
    accessorKey: "progress",
    header: "Progress",
    cell: ({ row }) => <Progress value={row.getValue("progress")} />,
  },
]

<DataTable columns={columns} data={MISSIONS} pageSize={6} />

Guidelines

Do
  • Use SortableHeader on every column the operator would think to sort by.
  • Render IDs, timestamps, and numeric columns with font-mono + tabular-nums.
  • Show status as a Badge, not a colored cell — the badge takes color; the row stays scannable.
Don't
  • Don't paginate client-side past a few hundred rows — swap in server-side pagination.
  • Don't nest interactive controls (button-in-row) unless there's a clear affordance — reach for Context menu instead.
  • Don't stripe zebra rows in dense tables; borders are enough.

Props

PropTypeDefaultDescription
columnsColumnDef<TData, TValue>[]—Column defs from @tanstack/react-table — accessorKey, header, cell.
dataTData[]—The rows to render.
paginatedbooleantrueEnable client-side pagination. Defaults to true.
pageSizenumber10Rows per page when paginated.
emptyMessageReact.ReactNode"No results."Shown when data is empty.
classNamestring—