Skip to content
Generative UIComparison tableMenu

Comparison table

Options side by side with the best value in each row marked, the recommended option tinted, and a choose button per column. The attribute column stays put while options scroll.

Best values marked per row, the recommended option tinted, and a choose button per column.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/comparison-table.json

Usage

tsx
import { ComparisonTable } from "@/components/ui/chatcn/comparison-table"

<ComparisonTable
  title="Postgres for the staging environment"
  options={[{ id: "neon", name: "Neon", values: { price: 19, branching: true } }, ...]}
  attributes={[
    { key: "price", label: "Monthly price", type: "currency", better: "lower" },
    { key: "branching", label: "Database branching" },
  ]}
  onSelect={(option) => choose(option.id)}
/>

Rows with better mark the winning value with a check and the word Lowest or Highest. A tie across every option marks nothing. Booleans render as a check or a dash with hidden Yes and No.

Examples

Loading and streaming

Reserved columns and rows while options stream in.

Props

PropTypeNotes
optionsComparisonOption[]id, name, description?, values, recommended?
attributesComparisonAttribute[]key, label, type?, better?, unit?, hint?
markBestbooleanDefault true
onSelect, selectLabel, selectedIdAdds a choose row; the chosen option locks the others
expectedOptionsnumberColumns reserved while streaming
currency, locale, footer
loading, streamingboolean

Keyboard

KeyAction
TabFocus the scroll region, then each choose button
Arrow keysScroll the table when it is wider than the answer

Accessibility

  • A real table with column headers for options and row headers for attributes, captioned with the title.
  • Best values are marked with a word and an icon, not weight or color alone.

Motion

  • Button press only. Choosing an option swaps its label to Chosen with no movement.