Eval table

Evaluation runs side by side: scores per run, the diff against the baseline, failing rows first, and the full output one keypress away.

Part of Pro, $99 once. What you get

ProSince 0.1.0
Runs
State
Theme
Accent

Press a header and the rows travel to their new order on a spring, regressions first, so you can follow one case as it moves.

Install#

Eval table is part of PixilUI Pro

  • Every Pro item, 2 today and each one added later
  • Installs with shadcn, npx pixilui or MCP
  • The source, Copy prompt and agent notes on every page

$99once

100 founder spots at $99 when Pro opens

The launch email, then product news. Unsubscribe anytime.

  • Access as soon as you pay
  • Updates for life
  • A full refund within 14 days if you have not installed or copied any Pro source. After that, a refund only when an item is broken and we cannot fix it within 14 days of your report.

Adds components/pixilui/eval-table.tsx. Needs motion, clsx, tailwind-merge.

Usage#

Use it when

  • Comparing a candidate prompt, model or agent version against a baseline on the same eval set.
  • A release review where the question is which cases got worse, and why.
  • Pasting a run comparison into a pull request or a doc with Copy as markdown.

Use something else when

  • A single run's score over time: use a chart.
  • Thousands of cases at once: page or virtualise them first; the table renders every row.
  • A general data grid with editing: this table only reads.

API#

PropTypeDefaultDescription
runsrequiredEvalTableRun[]The runs to compare, left to right. Two is the usual case; more columns scroll sideways.
casesrequiredEvalTableCase[]The eval cases, one row each.
baselinestringRun the diff and status compare against. Defaults to the first run.
candidatestringRun being judged. Defaults to the last run.
sortEvalTableSortControlled sort.
defaultSortEvalTableSort{ key: "status", direction: "asc" }Starting sort when uncontrolled: failing rows first.
onSortChange(sort: EvalTableSort) => voidRuns when a header is pressed.
defaultExpandedstring[][]Rows open at first render, by case id.
onCopy(markdown: string) => void | Promise<void>Receives the table as markdown, in the current order. Leave it out and the clipboard gets it. Return a promise to show pending.
formatScore(score: number) => stringdefaultFormatFormats scores and diffs. Defaults to two decimals.
loadingbooleanfalseShows placeholder rows and sets aria-busy while results load.
labelsPartial<EvalTableLabels>Copy overrides, for translation and house terms.

Also takes every native <div> attribute except onCopy, and a ref to it.

Keyboard#

Tab
Moves through Copy as markdown, the sortable headers, then into the rows (one row is in the tab order).
Enter
On a header, sorts by it; pressing again flips the direction. On a row, opens or closes its full output.
ArrowDownArrowUp
Moves between rows.
HomeEnd
Jumps to the first or last row.
ArrowRightArrowLeft
Opens or closes the focused row.

Accessibility#

  • A real table with an accessible name; headers are column headers with aria-sort on the sorted one.
  • Each row's case is a button with aria-expanded that controls its detail row.
  • Pass and fail are written out for screen readers beside each score; colour is never the only signal.
  • Rows use a roving tab index, so the table is one Tab stop however long it is.
  • Copy results are announced in a polite live region; loading sets aria-busy on the table.

Motion#

  • Sorting moves rows to their new places on the smooth spring, so you can follow a case as it travels.
  • Opening a row grows its detail on the morph spring; closing shrinks it on the smooth spring, never overshooting.
  • The row chevron and the sort arrow turn on the snappy spring.
  • Copy as markdown morphs to Copied and back with the button's label swap.
  • Reduced motion: rows jump to their places, and the detail fades in without growing.

Responsive#

  • Fills its container. Columns keep their natural width; narrower than the table, it scrolls sideways inside its own frame.
  • Give the root a height (or max height) and the header stays put while the rows scroll under it.
  • The detail shows outputs side by side from 640px, stacked below.

Performance#

  • Sorting is memoised on cases and sort; only open rows render their outputs.

Notes for AI#

Also in the markdown page and llms.txt
  1. Pass runs in display order and cases with results keyed by run id; the first run is the baseline and the last the candidate unless you say otherwise.
  2. Status compares candidate with baseline: regressed (passed before, fails now), failing, fixed, passing. The default sort puts regressions first, biggest drop first.
  3. Set a height on the root (h-96, max-h-[70vh]) for the sticky header to matter.
  4. Use onCopy to send the markdown somewhere other than the clipboard, such as a pull request comment.
  5. evalTableMarkdown, evalTableStatus and evalTableDiff are exported for use outside the table.