Pricing Table
A responsive pricing grid with highlighted tier and feature lists.
Installation
npx shadcn@latest add @hazine/pricing-tableSource
import * as React from "react"
import { CheckIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
export interface PricingTier {
name: string
price: string
priceNote?: string
description: string
features: string[]
action: { label: string; href: string }
highlighted?: boolean
badge?: string
}
interface PricingTableProps extends React.ComponentProps<"div"> {
tiers: PricingTier[]
}
export function PricingTable({ tiers, className, ...props }: PricingTableProps) {
return (
<div
className={cn(
"grid gap-6 sm:grid-cols-2 lg:grid-cols-3",
className
)}
{...props}
>
{tiers.map((tier) => (
<Card
key={tier.name}
className={cn(
"flex flex-col",
tier.highlighted && "border-primary shadow-md"
)}
>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle>{tier.name}</CardTitle>
{tier.badge && <Badge>{tier.badge}</Badge>}
</div>
<CardDescription>{tier.description}</CardDescription>
</CardHeader>
<CardContent className="flex flex-1 flex-col gap-6">
<div className="flex items-baseline gap-1.5">
<span className="text-4xl font-semibold tracking-tight">
{tier.price}
</span>
{tier.priceNote && (
<span className="text-sm text-muted-foreground">
{tier.priceNote}
</span>
)}
</div>
<ul className="flex flex-col gap-2.5 text-sm">
{tier.features.map((feature) => (
<li key={feature} className="flex items-start gap-2">
<CheckIcon className="mt-0.5 size-4 shrink-0 text-primary" />
{feature}
</li>
))}
</ul>
</CardContent>
<CardFooter>
<Button
className="w-full"
variant={tier.highlighted ? "default" : "outline"}
asChild
>
<a href={tier.action.href}>{tier.action.label}</a>
</Button>
</CardFooter>
</Card>
))}
</div>
)
}
Dependencies
- badge
- button
- card
- lucide-react