caliper uidocs

Comparison block

Block

The switch, row by row: the same task the old way and with your product, side by side.

Installs components/ui/comparison-block.tsxDepends on lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/comparison-block.json

Why switch

Month end, before and after

  • Matching bank lines

    Spreadsheets: VLOOKUPs across three exports, rerun after every correction.

    With Halden: Matched as each line lands, with the rule that matched it.

  • Finding a mismatch

    Spreadsheets: Scroll until the totals stop disagreeing.

    With Halden: Six lines, each with the likeliest invoice and who approved it.

  • Audit evidence

    Spreadsheets: Forty files, renamed by hand in October.

    With Halden: One export auditors can sample.

  • Time to close

    Spreadsheets: Nine working days.

    With Halden: A morning.

When to use #

Use it for

  • Buyers already do the job another way and need a reason to change.
  • Each difference is concrete enough to fit one line.

Skip it when

  • Naming competitors you cannot substantiate.
  • A feature checklist; use the pricing comparison.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/comparison-block.json

Adds its 4 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { type ReactNode } from "react"
import { ComparisonBlock } from "@/components/ui/comparison-block"

function Frame({ children }: { children: ReactNode }) {
  return <div className="w-full overflow-hidden rounded-[14px] shadow-[0_0_0_1px_var(--border)]">{children}</div>;
}

const comparisons: Parameters<typeof ComparisonBlock>[0] = { eyebrow: "Why switch", title: "Month end, before and after", beforeLabel: "Spreadsheets", afterLabel: "With Halden", rows: [
    { topic: "Matching bank lines", before: "VLOOKUPs across three exports, rerun after every correction.", after: "Matched as each line lands, with the rule that matched it." },
    { topic: "Finding a mismatch", before: "Scroll until the totals stop disagreeing.", after: "Six lines, each with the likeliest invoice and who approved it." },
    { topic: "Audit evidence", before: "Forty files, renamed by hand in October.", after: "One export auditors can sample." },
    { topic: "Time to close", before: "Nine working days.", after: "A morning." },
  ] };

export function ComparisonBlockDemo() {
  return <Frame><ComparisonBlock {...comparisons} /></Frame>;
}

API reference #

ComparisonBlock

component
PropTypeDefaultDescription
eyebrowstring—
title *string—
leadstring—
beforeLabel *string—e.g. "Spreadsheets".
afterLabel *string—e.g. "With Halden".
rows *readonly BlockComparisonRow[]—
footnotestring—
classNamestring—

Accessibility #

It is built on native elements and keeps aria-hidden in step with state.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.