Skip to content
Sign in
CommerceSpec compareMenu

Spec comparePro

Products side by side, built around what differs, with the best value ticked and matching specs folded.

ProThree daypacks with what differs marked and the matching specs folded away.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/spec-compare

Usage

tsx
import { SpecCompare } from "@/components/ui/chatcn/pro/spec-compare"

<SpecCompare
  products={picks}
  specs={[
    { id: "wt", label: "Weight", values: { tarn: 840, cairn: 690 }, unit: "g", better: "lower" },
    { id: "water", label: "Waterproof", values: { tarn: true, cairn: true } },
  ]}
  recommendedId="tarn"
  defaultOnlyDifferences
  onChoose={choose}
/>

A row whose values differ gets a thin accent rule at its start edge and full ink; a row every product shares turns a gray step quieter. Give a numeric row better and its best value gets a tick (a tie across every product marks nothing). Only differences folds the shared rows into one line that says how many match and opens them again. Booleans read as a tick or a dash with Yes or No for screen readers; a missing value says Not listed. The spec column is sticky, so on a phone the products scroll under it.

Examples

States

ProEvery row with shared ones quieter, too few products and loading.

Props

PropTypeNotes
products{ id, title, image?, merchant?, price, salePrice? }[]Two to four
specs{ id, label, values, better?: "higher" | "lower", unit? }[]Values by product id: text, number, boolean or null
currency, localestringPrices format with Intl, tabular figures. Default USD, en-US
onlyDifferences, defaultOnlyDifferences, onOnlyDifferencesChangebooleanFold shared rows
recommendedIdstringMarks the agent's pick
onChoose, chosenId(id) => void, stringAdds Choose under each column
loadingbooleanSkeleton columns
labelsPartial<SpecCompareLabels>Every string, for translation

Keyboard

KeyAction
TabThe switch, the fold line, then each Choose
SpaceToggle Only differences

Accessibility

  • A real table with a caption, column headers per product and row headers per spec.
  • Best values carry the word Best (visible from 640 px, hidden text below).
  • Choose buttons use aria-pressed; the fold line uses aria-expanded.

Motion

The switch thumb slides in 150 ms and the fold chevron turns in 150 ms. Rows appear without animation, so a long table never shuffles while you read it.