Minimal grey pricing cards with price, dotted plan name, a full-width button and a dotted feature list. React and Tailwind CSS.
MinimalPricingCards.tsx
// Minimal pricing cards in light grey: price, dotted plan name and description,
// a full-width button (dark for the featured plan) and a dotted feature list.
// Pure Tailwind, no dependencies. Works with Tailwind v3 and v4.
type Plan = { name: string; price: string; period?: string; description: string; cta: string; href?: string; features: string[]; featured?: boolean };
type Props = {
heading?: string;
plans?: Plan[];
};
const DEFAULT_PLANS: Plan[] = [
{ name: "Brand starter", price: "$2,400", period: "/ project", description: "A logo, colour palette and type system for a new business.", cta: "Start a project", features: ["Logo and wordmark", "Colour and type", "One-page guidelines"] },
{ name: "Website", price: "$6,800", period: "/ project", description: "Design and build of a fast marketing site, up to eight pages.", cta: "Book a call", features: ["Design in Figma", "Next.js build", "CMS for your team", "Launch support"], featured: true },
{ name: "Retainer", price: "$3,200", period: "/ month", description: "Ongoing design for teams that need a steady pair of hands.", cta: "Get in touch", features: ["Two days a week", "Weekly check-ins", "Pause any month"] },
];
const Dot = ({ size = "h-[5px] w-[5px]" }: { size?: string }) => <span aria-hidden className={`inline-block shrink-0 rounded-full bg-current ${size}`} />;
export default function MinimalPricing({ heading = "Pricing", plans = DEFAULT_PLANS }: Props) {
return (
<section className="bg-white px-4 py-20 font-['Inter',ui-sans-serif,system-ui,sans-serif] text-black antialiased md:px-8 md:py-28">
<div className="mx-auto max-w-7xl">
<h2 className="mb-16 text-[clamp(2.5rem,6vw,5rem)] font-semibold leading-none tracking-[-0.04em] md:mb-24">{heading}</h2>
<ul className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3">
{plans.map((plan) => (
<li key={plan.name} className="flex flex-col bg-[#F9F9F9]">
<div className="flex flex-col gap-4 p-6 md:p-7">
<p className="flex items-baseline gap-3">
<span className="text-4xl font-bold">{plan.price}</span>
{plan.period && <span className="font-medium">{plan.period}</span>}
</p>
<h3 className="flex items-center gap-2.5 font-semibold text-[#1A1A1A]">
<Dot />
{plan.name}
</h3>
<p className="text-sm leading-6 text-[#1A1A1A]">{plan.description}</p>
</div>
<a
href={plan.href ?? "#"}
className={`mx-6 py-3.5 text-center text-sm font-semibold transition-colors md:mx-7 ${plan.featured ? "bg-black text-white hover:bg-[#1A1A1A]" : "bg-white text-black hover:bg-black hover:text-white"}`}
>
{plan.cta}
</a>
<div className="flex flex-col gap-3 p-6 md:px-5 md:py-7">
<p className="text-sm font-bold leading-6 text-[#1A1A1A]">What's included</p>
<ul className="flex flex-col gap-2.5 px-2.5">
{plan.features.map((f) => (
<li key={f} className="flex items-center gap-2.5 text-sm font-medium text-[#1A1A1A]">
<Dot />
{f}
</li>
))}
</ul>
</div>
</li>
))}
</ul>
</div>
</section>
);
}
How to use it
- Make sure your Next.js or React project has Tailwind CSS set up (v3 or v4 both work).
- Create
components/MinimalPricingCards.tsxand paste the code. - Import it into a page and replace the sample text and images with your own.
