Pricing plans
Monthly or yearly plans with a recommended one.
Choose a plan for Northwind
Prices are per employee, per month, excluding VAT.
Save 20% yearly
Plan
Growth includes
- Everything in Starter
- Payroll exports
- Onboarding checklists
- Performance reviews
£7.20 per employee / month, billed yearly
pricing-plans.tsx
"use client";
import { useState } from "react";
import { LuArrowRight, LuBuilding2, LuCheck, LuRocket, LuSprout } from "react-icons/lu";
import { Badge, Button, RadioCard, RadioGroup, Segment, SegmentedControl } from "@nexera-ui/react";
type Billing = "monthly" | "yearly";
const money = new Intl.NumberFormat("en-GB", { style: "currency", currency: "GBP" });
/** Price per employee per month; yearly billing is 20 % cheaper. */
const PLANS = [
{
id: "starter",
name: "Starter",
icon: <LuSprout />,
monthly: 5,
seats: "Up to 25 employees",
features: ["Employee directory", "Leave requests and approvals", "Mobile app"],
},
{
id: "growth",
name: "Growth",
icon: <LuRocket />,
monthly: 9,
seats: "Up to 250 employees",
features: [
"Everything in Starter",
"Payroll exports",
"Onboarding checklists",
"Performance reviews",
],
},
{
id: "scale",
name: "Scale",
icon: <LuBuilding2 />,
monthly: 14,
seats: "Unlimited employees",
features: [
"Everything in Growth",
"SAML single sign-on",
"Audit log",
"Dedicated success manager",
],
},
] as const;
const priceFor = (monthly: number, billing: Billing) =>
billing === "yearly" ? monthly * 0.8 : monthly;
/** Pricing plans: monthly or yearly billing, a recommended plan and what each plan includes. */
export default function PricingPlans() {
const [billing, setBilling] = useState<Billing>("yearly");
const [planId, setPlanId] = useState<string>("growth");
const plan = PLANS.find((p) => p.id === planId) ?? PLANS[1];
const price = priceFor(plan.monthly, billing);
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<div className="mx-auto grid w-full max-w-4xl gap-6">
<header className="flex flex-wrap items-end justify-between gap-4">
<div className="grid gap-1">
<h2 className="text-heading-h2 text-primary">Choose a plan for Northwind</h2>
<p className="text-body-default text-secondary">
Prices are per employee, per month, excluding VAT.
</p>
</div>
<div className="flex flex-wrap items-center gap-2">
<SegmentedControl
aria-label="Billing period"
selectedKeys={[billing]}
onSelectionChange={(keys) => {
const [next] = [...keys];
if (next === "monthly" || next === "yearly") setBilling(next);
}}
>
<Segment id="monthly" label="Monthly" />
<Segment id="yearly" label="Yearly" />
</SegmentedControl>
<Badge tone="success" label="Save 20% yearly" />
</div>
</header>
<RadioGroup
label="Plan"
type="card"
orientation="horizontal"
value={planId}
onChange={setPlanId}
name="plan"
>
{PLANS.map((p) => (
<RadioCard
key={p.id}
value={p.id}
icon={p.icon}
title={p.name}
{...(p.id === "growth" ? { meta: "Recommended" } : {})}
description={`${money.format(priceFor(p.monthly, billing))} per employee / month. ${p.seats}.`}
/>
))}
</RadioGroup>
<section
aria-labelledby="plan-summary"
className="grid gap-4 rounded-xl border border-default bg-surface p-5 shadow-xs @3xl:grid-cols-[1fr_auto] @3xl:items-end"
>
<div className="grid gap-3">
<h3 id="plan-summary" className="text-heading-h4 text-primary">
{plan.name} includes
</h3>
<ul className="grid gap-2 @3xl:grid-cols-2">
{plan.features.map((feature) => (
<li
key={feature}
className="flex items-center gap-2 text-body-default text-primary"
>
<LuCheck aria-hidden="true" className="size-4 shrink-0 text-status-success-fg" />
{feature}
</li>
))}
</ul>
</div>
<div className="grid gap-2 @3xl:justify-items-end">
<p className="text-body-small text-secondary">
<span className="text-heading-h3 text-primary">{money.format(price)}</span> per
employee / month
{billing === "yearly" ? ", billed yearly" : ""}
</p>
<Button size="lg" trailingIcon={<LuArrowRight />}>
Continue with {plan.name}
</Button>
</div>
</section>
</div>
</div>
);
}
More commerce and payments blocks
- CheckoutCard details, billing address and order total.
- Saved payment methodsChoose, add or remove a card.
- Order summaryItems, discounts and totals.
- PayslipEarnings and deductions with totals.
- Product galleryPhotos with thumbnails and zoom.
- Reviews and ratingsAverage score, breakdown and written reviews.
- Order trackingWhere an order is, step by step.