Pricing Single Card
Original · freeA single pricing plan card with feature list and CTA.
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/card-pricing-single.json"use client";
import { useId, useState } from "react";
import { motion, useReducedMotion } from "motion/react";
type BillingCycle = "monthly" | "annual";
interface Feature {
label: string;
included: boolean;
}
const FEATURES: Feature[] = [
{ label: "Up to 25 team members", included: true },
{ label: "Unlimited public projects", included: true },
{ label: "Advanced analytics dashboard", included: true },
{ label: "Priority email & chat support", included: true },
{ label: "Custom domains with SSL", included: true },
{ label: "SSO & SCIM provisioning", included: false },
{ label: "Dedicated success manager", included: false },
];
const PRICING: Record<BillingCycle, { amount: number; suffix: string; note: string }> = {
monthly: { amount: 29, suffix: "/mo", note: "Billed monthly, cancel anytime" },
annual: { amount: 23, suffix: "/mo", note: "Billed $276 yearly — save 20%" },
};
function CheckIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" className="h-3.5 w-3.5" aria-hidden="true">
<path
d="M4 10.5l3.5 3.5L16 5.5"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
function MinusIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" className="h-3.5 w-3.5" aria-hidden="true">
<path
d="M5 10h10"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
/>
</svg>
);
}
function SparkIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<path
d="M12 2.5l1.9 5.3 5.6.5-4.3 3.6 1.4 5.4L12 19.4l-4.6 2.4 1.4-5.4-4.3-3.6 5.6-.5L12 2.5z"
fill="currentColor"
/>
</svg>
);
}
function SpinnerIcon() {
return (
<svg viewBox="0 0 24 24" fill="none" className="h-4 w-4" aria-hidden="true">
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="3" className="opacity-25" />
<path
d="M21 12a9 9 0 0 0-9-9"
stroke="currentColor"
strokeWidth="3"
strokeLinecap="round"
/>
</svg>
);
}
function PricingCard() {
const [cycle, setCycle] = useState<BillingCycle>("annual");
const [status, setStatus] = useState<"idle" | "loading" | "done">("idle");
const reduceMotion = useReducedMotion();
const headingId = useId();
const priceId = useId();
const price = PRICING[cycle];
const isAnnual = cycle === "annual";
function handleSubscribe() {
if (status !== "idle") return;
setStatus("loading");
window.setTimeout(() => {
setStatus("done");
window.setTimeout(() => setStatus("idle"), 2200);
}, 1400);
}
return (
<div
className="group relative w-full max-w-sm rounded-3xl border border-slate-200 bg-white p-1 shadow-[0_1px_2px_rgba(15,23,42,0.06),0_12px_40px_-12px_rgba(15,23,42,0.18)] transition-shadow duration-300 hover:shadow-[0_1px_2px_rgba(15,23,42,0.08),0_24px_60px_-16px_rgba(79,70,229,0.28)] dark:border-slate-800 dark:bg-slate-900 dark:shadow-[0_1px_2px_rgba(0,0,0,0.4),0_18px_50px_-18px_rgba(0,0,0,0.7)]"
>
{/* gradient hairline top accent */}
<div
aria-hidden="true"
className="pointer-events-none absolute inset-x-8 top-0 h-px bg-gradient-to-r from-transparent via-indigo-400/70 to-transparent dark:via-indigo-400/50"
/>
<div className="relative rounded-[1.375rem] bg-white p-7 dark:bg-slate-900">
<div className="flex items-start justify-between gap-4">
<div>
<div className="flex items-center gap-2">
<span className="flex h-8 w-8 items-center justify-center rounded-xl bg-indigo-600 text-white shadow-sm shadow-indigo-600/30">
<SparkIcon />
</span>
<h3
id={headingId}
className="text-base font-semibold tracking-tight text-slate-900 dark:text-white"
>
Pro
</h3>
</div>
<p className="mt-3 text-sm leading-relaxed text-slate-500 dark:text-slate-400">
For growing teams shipping real products — everything you need to scale.
</p>
</div>
<span className="shrink-0 rounded-full bg-emerald-50 px-2.5 py-1 text-[0.7rem] font-semibold uppercase tracking-wide text-emerald-700 ring-1 ring-inset ring-emerald-600/20 dark:bg-emerald-500/10 dark:text-emerald-300 dark:ring-emerald-400/25">
Popular
</span>
</div>
{/* Billing toggle */}
<div
role="group"
aria-label="Billing period"
className="mt-6 grid grid-cols-2 gap-1 rounded-xl bg-slate-100 p-1 dark:bg-slate-800/80"
>
{(["monthly", "annual"] as BillingCycle[]).map((value) => {
const active = cycle === value;
return (
<button
key={value}
type="button"
aria-pressed={active}
onClick={() => setCycle(value)}
className={`relative rounded-lg px-3 py-1.5 text-sm font-medium capitalize outline-none transition-colors focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-100 dark:focus-visible:ring-offset-slate-800 ${
active
? "bg-white text-slate-900 shadow-sm dark:bg-slate-950 dark:text-white"
: "text-slate-500 hover:text-slate-700 dark:text-slate-400 dark:hover:text-slate-200"
}`}
>
{value}
{value === "annual" && (
<span className="ml-1 text-[0.65rem] font-bold text-emerald-600 dark:text-emerald-400">
−20%
</span>
)}
</button>
);
})}
</div>
{/* Price */}
<div className="mt-6 flex items-end gap-1" aria-live="polite">
<motion.span
key={cycle}
id={priceId}
initial={reduceMotion ? false : { opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.28, ease: [0.22, 1, 0.36, 1] }}
className="text-5xl font-semibold tracking-tight text-slate-900 tabular-nums dark:text-white"
>
${price.amount}
</motion.span>
<span className="pb-1.5 text-base font-medium text-slate-400 dark:text-slate-500">
{price.suffix}
</span>
</div>
<p className="mt-1.5 text-xs text-slate-500 dark:text-slate-400">{price.note}</p>
{/* CTA */}
<button
type="button"
onClick={handleSubscribe}
disabled={status === "loading"}
aria-label={isAnnual ? "Subscribe to Pro, billed annually" : "Subscribe to Pro, billed monthly"}
className="mt-6 flex w-full items-center justify-center gap-2 rounded-xl bg-indigo-600 px-4 py-3 text-sm font-semibold text-white shadow-sm shadow-indigo-600/30 outline-none transition-all duration-200 hover:bg-indigo-500 hover:shadow-md hover:shadow-indigo-600/40 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white active:scale-[0.985] disabled:cursor-not-allowed disabled:opacity-70 dark:focus-visible:ring-offset-slate-900"
>
{status === "loading" && (
<span className="cpsingle-spin motion-reduce:animate-none">
<SpinnerIcon />
</span>
)}
{status === "loading"
? "Processing…"
: status === "done"
? "You're all set ✓"
: "Start 14-day free trial"}
</button>
<p className="mt-3 text-center text-xs text-slate-400 dark:text-slate-500">
No credit card required
</p>
{/* Features */}
<div className="my-6 h-px w-full bg-slate-100 dark:bg-slate-800" />
<ul className="space-y-3" aria-label="Plan features">
{FEATURES.map((feature) => (
<li key={feature.label} className="flex items-center gap-3 text-sm">
<span
className={`flex h-5 w-5 shrink-0 items-center justify-center rounded-full ${
feature.included
? "bg-indigo-50 text-indigo-600 ring-1 ring-inset ring-indigo-600/15 dark:bg-indigo-500/15 dark:text-indigo-300 dark:ring-indigo-400/20"
: "bg-slate-100 text-slate-400 dark:bg-slate-800 dark:text-slate-600"
}`}
>
{feature.included ? <CheckIcon /> : <MinusIcon />}
</span>
<span
className={
feature.included
? "text-slate-700 dark:text-slate-200"
: "text-slate-400 line-through decoration-slate-300 dark:text-slate-600 dark:decoration-slate-700"
}
>
{feature.label}
</span>
</li>
))}
</ul>
</div>
</div>
);
}
export default function CardPricingSingle() {
return (
<section className="relative w-full bg-slate-50 px-4 py-20 dark:bg-slate-950 sm:px-6 sm:py-28">
<style>{`
@keyframes cpsingle-spin {
to { transform: rotate(360deg); }
}
.cpsingle-spin {
display: inline-flex;
animation: cpsingle-spin 0.7s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
.cpsingle-spin { animation: none; }
}
`}</style>
<div className="mx-auto flex max-w-md flex-col items-center">
<div className="mb-10 text-center">
<span className="inline-flex items-center rounded-full bg-indigo-50 px-3 py-1 text-xs font-medium text-indigo-700 ring-1 ring-inset ring-indigo-600/15 dark:bg-indigo-500/10 dark:text-indigo-300 dark:ring-indigo-400/20">
Pricing
</span>
<h2 className="mt-4 text-2xl font-semibold tracking-tight text-slate-900 dark:text-white sm:text-3xl">
One plan, everything included
</h2>
<p className="mt-3 text-sm text-slate-500 dark:text-slate-400">
Toggle billing and subscribe — the card is fully interactive.
</p>
</div>
<PricingCard />
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
3D Tilt Cards
OriginalA responsive grid of cards that tilt in 3D toward your cursor with a light glare and lifted depth layers, powered by Framer Motion springs.

Spotlight Follow Cards
OriginalFeature cards where a soft radial spotlight and a glowing border chase the cursor on hover, with a staggered scroll reveal and an animated shimmer line.

3D Flip Cards
OriginalPricing-style cards that flip in 3D on hover or tap to reveal details on the back, keyboard accessible with a staggered entrance animation.

Animated Gradient Border Cards
OriginalCards wrapped in a live conic gradient border that rotates and speeds up on hover, with a shimmer sweep and a scrolling tag marquee.

Glow Effect Card
primitivesA reusable glow effect card for React and Tailwind, with hover and motion.

Neon Gradient Card
gradient-card.tsxA reusable neon gradient card for React and Tailwind, with hover and motion.

Spotlight Magic Card
card.tsxA reusable spotlight magic card for React and Tailwind, with hover and motion.

Tilt Spotlight Card
primitivesA reusable tilt spotlight card for React and Tailwind, with hover and motion.

Profile Card
OriginalA user profile card with avatar, stats and a follow toggle.

Product Card
OriginalA product card with image, price and add-to-cart feedback.

Stat Card
OriginalA metric card with value, trend arrow and a small sparkline.

Blog Card
OriginalA blog post card with cover image, tag and meta row.

