A great pricing page inspires confidence. It shows clarity, flexibility, and trust. When you design it well, users decide faster. In this tutorial, you will build a pricing page with HeroUI in Next.js. You will use a toggle switch to switch between monthly and yearly pricing. Cards will showcase the plans. TypeScript ensures type safety and a better developer experience.
Why a Pricing Page Matters
Pricing pages are not just about numbers. They drive conversions. A clear design persuades users to choose a plan. A confusing layout, however, drives them away. Transparency matters, and users must be able to understand options instantly. That’s why you will use HeroUI. It provides accessible, modern, and responsive components. Combined with Next.js, it delivers blazing-fast performance. Together, they create a pricing page that inspires trust.
Setting Up the Project

Project Structure
pricing-page/ ├── app/ │ ├── pricing/ │ │ └── page.tsx # Pricing page with cards and toggle │ ├── layout.tsx # Root layout for Next.js │ └── globals.css # Tailwind global styles ├── components/ │ ├── PricingToggle.tsx # Switch component for monthly/yearly toggle │ └── PricingCard.tsx # HeroUI Card component for plan details ├── public/ # Static assets like images or icons ├── styles/ │ └── theme.css # Optional extra theme or overrides ├── tailwind.config.js # Tailwind configuration ├── tsconfig.json # TypeScript configuration ├── package.json # Project dependencies and scripts └── README.md # Documentation for your project
Key Points
app/pricing/page.tsx: The main page, powered by Next.js App Router.components/: Holds reusable UI blocks like cards and toggles.public/: Stores logos, icons, and static media.styles/: Extra styling or global overrides.tailwind.config.js: Central place for customizing design tokens.
This structure keeps logic, UI, and configuration separated. It prevents bloated files and ensures maintainability. As your app grows, you can add more folders like hooks/ or utils/.
Creating the Pricing Toggle
The toggle is the heart of your page. It allows users to choose between monthly and yearly billing. Add a component PricingToggle.tsx:
"use client";
import { Switch } from "@heroui/react";
import { useState } from "react";
export default function PricingToggle({
onChange,
}: {
onChange: (isYearly: boolean) => void;
}) {
const [isYearly, setIsYearly] = useState(false);
return (
<div className="flex items-center justify-center gap-2 my-6">
<span>Monthly</span>
<Switch
isSelected={isYearly}
onValueChange={(checked) => {
setIsYearly(checked);
onChange(checked);
}}
/>
<span>Yearly</span>
</div>
);
}This toggle communicates billing preferences to the parent component. It starts with monthly as the default.
Designing the Pricing Card
A pricing card shows the plan. It includes title, price, features, and a button. HeroUI’s Card component makes this simple. Create PricingCard.tsx:
import { Card, CardBody, CardHeader, Button } from "@heroui/react";
type PricingCardProps = {
title: string;
price: string;
features: string[];
};
export default function PricingCard({
title,
price,
features,
}: PricingCardProps) {
return (
<Card className="max-w-lg">
<CardHeader className="text-center text-xl font-bold">{title}</CardHeader>
<CardBody>
<div className="text-center text-3xl font-semibold">{price}</div>
<ul className="mt-4 space-y-2">
{features.map((feature, idx) => (
<li key={idx} className="text-gray-600">
{feature}
</li>
))}
</ul>
<div className="mt-6 flex justify-center">
<Button color="primary">Choose Plan</Button>
</div>
</CardBody>
</Card>
);
}The card displays a clean layout. It encourages interaction and simplifies plan comparison.
Combining Cards and Toggle
Now, assemble the pricing page. Create app/pricing/page.tsx:
"use client";
import { useState } from "react";
import PricingToggle from "../../components/PricingToggle";
import PricingCard from "../../components/PricingCard";
export default function PricingPage() {
const [isYearly, setIsYearly] = useState(false);
const plans = [
{
title: "Starter",
monthly: "$10",
yearly: "$100",
features: ["1 Project", "Basic Support", "Community Access"],
},
{
title: "Pro",
monthly: "$30",
yearly: "$300",
features: ["10 Projects", "Priority Support", "Team Access"],
},
{
title: "Enterprise",
monthly: "$100",
yearly: "$1000",
features: ["Unlimited Projects", "Dedicated Support", "Custom Solutions"],
},
];
return (
<main className="flex flex-col items-center p-6">
<h1 className="text-4xl font-bold text-center mb-6">Choose Your Plan</h1>
<PricingToggle onChange={setIsYearly} />
<div className="grid gap-6 md:grid-cols-3">
{plans.map((plan, idx) => (
<PricingCard
key={idx}
features={plan.features}
price={isYearly ? plan.yearly : plan.monthly}
title={plan.title}
/>
))}
</div>
</main>
);
}This page connects the toggle to the cards. When the toggle changes, the price updates instantly. The experience feels smooth and responsive.
Launch an application
>npm run dev
http://localhost:3000/pricing


Improve Design with Tailwind CSS
PricingCard.tsx
import { Card, CardBody, CardHeader, Button } from "@heroui/react";
import { CheckBadgeIcon } from "@heroicons/react/24/solid";
type PricingCardProps = {
title: string;
price: string;
features: string[];
};
export default function PricingCard({
title,
price,
features,
}: PricingCardProps) {
return (
<Card className="max-w-sm rounded-2xl shadow-xl overflow-hidden ease-in-out bg-white dark:bg-gray-800">
<CardHeader className="text-center text-2xl font-extrabold p-6 bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600">
{title}
</CardHeader>
<CardBody className="p-8">
<div className="text-center text-4xl font-extrabold text-blue-600 dark:text-blue-400">
{price}
</div>
<ul className="mt-6 space-y-4">
{features.map((feature, idx) => (
<li
key={idx}
className="text-gray-700 dark:text-gray-300 flex items-center"
>
<CheckBadgeIcon className="text-green-500 h-6 w-6" />
{feature}
</li>
))}
</ul>
<div className="mt-8 flex justify-center">
<Button
className="w-full py-3 px-6 rounded-full font-bold text-lg hover:shadow-lg transition-shadow duration-300"
color="primary"
>
Choose Plan
</Button>
</div>
</CardBody>
</Card>
);
}
Add an icon in the switch component
PricingToggle.tsx:
"use client";
import { Switch } from "@heroui/react";
import { useState } from "react";
import { CalendarIcon, GiftIcon } from "@heroicons/react/24/solid";
export default function PricingToggle({
onChange,
}: {
onChange: (isYearly: boolean) => void;
}) {
const [isYearly, setIsYearly] = useState(false);
return (
<div className="flex items-center justify-center gap-2 my-6">
<span>Monthly</span>
<Switch
endContent={<CalendarIcon className="h6 w6" />}
isSelected={isYearly}
size="lg"
startContent={<GiftIcon className="h6 w6" />}
onValueChange={(checked) => {
setIsYearly(checked);
onChange(checked);
}}
/>
<span>Yearly</span>
</div>
);
}
Making It Inspirational
Your pricing page must inspire trust. Highlight the value, not just the cost. Use persuasive words in headings. Example: “Invest in Growth” instead of “Pricing Plans.” This mindset encourages users to see value beyond numbers. A toggle adds control. Users feel empowered to choose billing that suits them.
Best Practices for Pricing Pages

Why Next.js and HeroUI Shine Together
Next.js ensures fast loading with server-side rendering. HeroUI ensures an accessible and polished UI. Together, they speed up development and enhance UX. With TypeScript, you reduce errors. This stack makes you productive and gives users confidence.
Expanding Further
You can expand this pricing page. Add animations for the toggle. Highlight the most popular plan. Include testimonials below the cards. Show currency localization if you target global markets. Every extra touch improves trust and boosts conversions.
Finally
A pricing page is more than a table of numbers. It is persuasion through clarity, design, and trust. Using Next.js, HeroUI, and TypeScript, you can build a professional, conversion-driven page. A toggle adds flexibility, and HeroUI cards make plans attractive. You now hold the steps to inspire users to act. Build with intention, and your pricing page will become your best salesperson.
This article was originally published on Medium.



