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.
On this page
Best values marked per row, the recommended option tinted, and a choose button per column.
Installation
Usage
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
| Prop | Type | Notes |
|---|---|---|
options | ComparisonOption[] | id, name, description?, values, recommended? |
attributes | ComparisonAttribute[] | key, label, type?, better?, unit?, hint? |
markBest | boolean | Default true |
onSelect, selectLabel, selectedId | Adds a choose row; the chosen option locks the others | |
expectedOptions | number | Columns reserved while streaming |
currency, locale, footer | ||
loading, streaming | boolean |
Keyboard
| Key | Action |
|---|---|
Tab | Focus the scroll region, then each choose button |
Arrow keys | Scroll 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.