caliper uidocs

Comparison table

Block

A feature grid comparing plans or products row by row.

Installs components/ui/comparison-table.tsxDepends on lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/comparison-table.json
Compare plans
StarterTeamBusiness
Library
Components40200+200+
Blocks and screensWhole sections you can editNot includedIncludedIncluded
Agent interface kitNot includedIncludedIncluded
Support
CommunityIncludedIncludedIncluded
Email supportNot included2 days1 day
Seat managementNot includedNot includedIncluded

When to use #

Use it for

  • The details matter more than the headline price.

Skip it when

  • Fewer than four rows.

Installation #

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

Adds its 2 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 { ComparisonTable } from "@/components/ui/comparison-table"

const plans = [
  { id: "starter", name: "Starter", description: "For trying things out.", price: { monthly: 0, yearly: 0 }, features: ["40 components", "Community support", "Personal projects"], cta: "Start free" },
  { id: "team", name: "Team", description: "For shipping a product.", price: { monthly: 24, yearly: 19 }, features: ["Every component and block", "Private repository access", "Email support", "Unlimited projects"], cta: "Choose Team", highlighted: true, badge: "Most popular" },
  { id: "business", name: "Business", description: "For admin controls.", price: { monthly: 48, yearly: 40 }, features: ["Everything in Team", "Priority support", "Seat management", "Custom license terms"], cta: "Choose Business" },
  { id: "enterprise", name: "Enterprise", description: "For custom needs.", price: "Talk to us", features: ["Everything in Business", "Security review", "Dedicated contact"], cta: "Contact sales" },
];

const compare = [
  { id: "starter", name: "Starter" },
  { id: "team", name: "Team", highlight: true },
  { id: "business", name: "Business" },
];

const groups = [
  { title: "Library", rows: [
    { label: "Components", values: { starter: "40", team: "200+", business: "200+" } },
    { label: "Blocks and screens", hint: "Whole sections you can edit", values: { starter: false, team: true, business: true } },
    { label: "Agent interface kit", values: { starter: false, team: true, business: true } },
  ] },
  { title: "Support", rows: [
    { label: "Community", values: { starter: true, team: true, business: true } },
    { label: "Email support", values: { starter: false, team: "2 days", business: "1 day" } },
    { label: "Seat management", values: { starter: false, team: false, business: true } },
  ] },
];

export function ComparisonTableDemo() {
  return (
    <ComparisonTable plans={compare} groups={groups} />
  );
}

API reference #

ComparisonTable

component
PropTypeDefault
plans *readonly ComparisonPlan[]—
groups *readonly ComparisonGroup[]—
captionstring"Compare plans"
classNamestring—

Accessibility #

It exposes region semantics, with aria-label and aria-hidden kept 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.