Pricing layouts that make the differences between plans easy to read. Replace the numbers and features with your own.
Three tiers
Three familiar plan cards. The popular option uses your primary color, with checkmarks and bottom-aligned actions.
Simple pricing
Pick a plan and ship. Upgrade when the team grows.
Hobby
$0/mo
For side projects and trying the kit.
- 3 projects
- Basic blocks
- Community support
Pro
Popular$29/mo
For teams shipping real product surfaces.
- Unlimited projects
- All blocks
- Priority support
- Team seats
Enterprise
Custom
Security, SLAs, and dedicated onboarding.
- SSO & audit logs
- Custom contracts
- Dedicated support
"use client";import { Button } from "@/components/ui/button";import { cn } from "@/lib/utils";type Pricing01Props = { className?: string;};function CheckIcon({ className }: { className?: string }) { return ( <svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className={className} > <path d="M5 12.5l4.5 4.5L19 7" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /> </svg> );}const PLANS = [ { name: "Hobby", price: "$0", period: "/mo", description: "For side projects and trying the kit.", features: ["3 projects", "Basic blocks", "Community support"], cta: "Start free", featured: false, }, { name: "Pro", price: "$29", period: "/mo", description: "For teams shipping real product surfaces.", features: [ "Unlimited projects", "All blocks", "Priority support", "Team seats", ], cta: "Get Pro", featured: true, }, { name: "Enterprise", price: "Custom", period: "", description: "Security, SLAs, and dedicated onboarding.", features: ["SSO & audit logs", "Custom contracts", "Dedicated support"], cta: "Talk to us", featured: false, },] as const;export function Pricing01({ className }: Pricing01Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="mx-auto max-w-md text-center"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> Simple pricing </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> Pick a plan and ship. Upgrade when the team grows. </p> </div> <ul className="mt-8 grid grid-cols-1 gap-3 @[40rem]:grid-cols-3"> {PLANS.map((plan) => ( <li key={plan.name} className={cn( "flex flex-col rounded-xl p-5", plan.featured ? "bg-primary text-primary-foreground" : "bg-muted text-foreground", )} > <div className="flex items-baseline justify-between gap-2"> <p className="text-sm font-medium tracking-wide">{plan.name}</p> {plan.featured ? ( <span className="rounded-md bg-primary-foreground px-1.5 py-0.5 text-[11px] tracking-wide text-primary"> Popular </span> ) : null} </div> <p className="mt-3 flex items-baseline gap-0.5"> <span className="text-3xl font-medium tracking-tight"> {plan.price} </span> {plan.period ? ( <span className={cn( "text-xs tracking-wide", plan.featured ? "text-primary-foreground/70" : "text-muted-foreground", )} > {plan.period} </span> ) : null} </p> <p className={cn( "mt-2 text-xs tracking-wide", plan.featured ? "text-primary-foreground/70" : "text-muted-foreground", )} > {plan.description} </p> <ul className="mt-5 flex flex-col gap-2"> {plan.features.map((feature) => ( <li key={feature} className={cn( "flex items-start gap-2 text-xs tracking-wide", plan.featured ? "text-primary-foreground/85" : "text-muted-foreground", )} > <CheckIcon className={cn( "mt-0.5 size-3.5 shrink-0", plan.featured ? "text-primary-foreground" : "text-foreground", )} /> <span>{feature}</span> </li> ))} </ul> <div className="mt-auto pt-6"> <Button type="button" size="sm" className="w-full" variant={plan.featured ? "secondary" : "default"} > {plan.cta} </Button> </div> </li> ))} </ul> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add pricing-01Usage
import { Pricing01 } from "@/components/blocks/pricing/pricing-01"<Pricing01 />Billing toggle
A monthly and yearly toggle above three equal-height cards. Prices roll with a number ticker when billing changes.
Pay monthly or yearly
Yearly billing saves about 20% on every plan.
Starter
$15/mo
Billed yearly
Solo builders and early launches.
- 10 projects
- Core blocks
- Email support
Team
$39/mo
Billed yearly
Growing product and design teams.
- Unlimited projects
- All blocks
- Shared library
- Slack support
Business
$79/mo
Billed yearly
Orgs that need control and scale.
- Everything in Team
- SSO
- Audit log
- Priority SLA
"use client";import { useState } from "react";import { Button } from "@/components/ui/button";import { cn } from "@/lib/utils";type Pricing02Props = { className?: string;};const PLANS = [ { name: "Starter", monthly: 19, yearly: 15, description: "Solo builders and early launches.", features: ["10 projects", "Core blocks", "Email support"], }, { name: "Team", monthly: 49, yearly: 39, description: "Growing product and design teams.", features: [ "Unlimited projects", "All blocks", "Shared library", "Slack support", ], }, { name: "Business", monthly: 99, yearly: 79, description: "Orgs that need control and scale.", features: ["Everything in Team", "SSO", "Audit log", "Priority SLA"], },] as const;function TickerDigit({ digit, delay }: { digit: string; delay: number }) { const n = Number(digit); return ( <span className="relative inline-block h-[1em] w-[0.62em] overflow-hidden"> <span aria-hidden className="absolute inset-x-0 top-0 flex flex-col will-change-transform" style={{ transform: `translateY(${-n}em)`, transition: `transform 700ms cubic-bezier(0.22, 1, 0.36, 1) ${delay}ms`, }} > {Array.from({ length: 10 }, (_, i) => ( <span key={i} className="flex h-[1em] items-center justify-center tabular-nums" > {i} </span> ))} </span> <span className="invisible tabular-nums">{digit}</span> </span> );}function PriceTicker({ value }: { value: number }) { const digits = String(value).split(""); return ( <span className="inline-flex items-baseline"> <span className="mr-0.5">$</span> <span className="inline-flex" aria-label={`${value}`}> {digits.map((digit, index) => ( <TickerDigit key={index} digit={digit} delay={index * 60} /> ))} </span> </span> );}export function Pricing02({ className }: Pricing02Props) { const [yearly, setYearly] = useState(true); return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="flex flex-col items-center gap-5 text-center"> <div className="max-w-md"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> Pay monthly or yearly </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> Yearly billing saves about 20% on every plan. </p> </div> <div className="inline-flex rounded-lg bg-muted p-1"> <button type="button" onClick={() => setYearly(false)} className={cn( "rounded-md px-3 py-1.5 text-xs tracking-wide", !yearly ? "bg-background text-foreground" : "text-muted-foreground", )} > Monthly </button> <button type="button" onClick={() => setYearly(true)} className={cn( "rounded-md px-3 py-1.5 text-xs tracking-wide", yearly ? "bg-background text-foreground" : "text-muted-foreground", )} > Yearly </button> </div> </div> <ul className="mt-8 grid grid-cols-1 items-stretch gap-3 @[40rem]:grid-cols-3"> {PLANS.map((plan) => { const price = yearly ? plan.yearly : plan.monthly; return ( <li key={plan.name} className="flex h-full flex-col rounded-xl bg-muted p-5" > <p className="text-sm font-medium tracking-wide text-foreground"> {plan.name} </p> <p className="mt-3 flex items-baseline gap-1 text-3xl font-medium tracking-tight text-foreground"> <PriceTicker value={price} /> <span className="text-xs font-normal tracking-wide text-muted-foreground"> /mo </span> </p> <p className="mt-1 text-[11px] tracking-wide text-muted-foreground"> {yearly ? "Billed yearly" : "Billed monthly"} </p> <p className="mt-3 text-xs tracking-wide text-muted-foreground"> {plan.description} </p> <ul className="mt-5 flex flex-col gap-2"> {plan.features.map((feature) => ( <li key={feature} className="text-xs tracking-wide text-muted-foreground" > {feature} </li> ))} </ul> <div className="mt-auto pt-6"> <Button type="button" size="sm" className="w-full"> Choose {plan.name} </Button> </div> </li> ); })} </ul> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add pricing-02Usage
import { Pricing02 } from "@/components/blocks/pricing/pricing-02"<Pricing02 />Comparison table
A feature matrix across three plans, with the Pro column filled in your primary color.
Compare plans
Everything side by side — pick what you need now.
| Feature | Hobby $0/mo | Pro $29/mo | Business $99/mo |
|---|---|---|---|
| Projects | 3 | Unlimited | Unlimited |
| Blocks | Core | All | All + private |
| Seats | 1 | 10 | Unlimited |
| Support | Community | Priority | Dedicated |
| SSO | — | — | Included |
| Audit log | — | — | Included |
"use client";import { Button } from "@/components/ui/button";import { cn } from "@/lib/utils";type Pricing03Props = { className?: string;};const FEATURES = [ { name: "Projects", hobby: "3", pro: "Unlimited", business: "Unlimited" }, { name: "Blocks", hobby: "Core", pro: "All", business: "All + private" }, { name: "Seats", hobby: "1", pro: "10", business: "Unlimited" }, { name: "Support", hobby: "Community", pro: "Priority", business: "Dedicated" }, { name: "SSO", hobby: "—", pro: "—", business: "Included" }, { name: "Audit log", hobby: "—", pro: "—", business: "Included" },] as const;const PLANS = [ { key: "hobby", name: "Hobby", price: "$0", cta: "Start free" }, { key: "pro", name: "Pro", price: "$29", cta: "Get Pro", featured: true }, { key: "business", name: "Business", price: "$99", cta: "Get Business" },] as const;/** Solid column fill + hairline drawn above it (not a translucent border overlay). */const rowRule = "before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:z-10 before:h-px before:bg-border";const featuredRowRule = "before:pointer-events-none before:absolute before:inset-x-0 before:top-0 before:z-10 before:h-px before:bg-primary-foreground/25";export function Pricing03({ className }: Pricing03Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="mx-auto max-w-md text-center"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> Compare plans </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> Everything side by side — pick what you need now. </p> </div> <div className="mt-8 overflow-x-auto rounded-xl bg-muted p-2 @[40rem]:p-3"> <table className="w-full min-w-[36rem] border-separate border-spacing-0 text-left"> <thead> <tr> <th className="relative z-0 w-[28%] px-3 py-3 text-xs font-medium tracking-wide text-muted-foreground"> Feature </th> {PLANS.map((plan) => ( <th key={plan.key} className={cn( "relative z-0 px-3 py-3 text-center", plan.featured && "rounded-t-lg bg-primary text-primary-foreground", )} > <div className="relative z-20"> <p className={cn( "text-sm font-medium tracking-wide", plan.featured ? "text-primary-foreground" : "text-foreground", )} > {plan.name} </p> <p className={cn( "mt-1 text-lg font-medium tracking-tight", plan.featured ? "text-primary-foreground" : "text-foreground", )} > {plan.price} <span className={cn( "text-xs font-normal", plan.featured ? "text-primary-foreground/70" : "text-muted-foreground", )} > /mo </span> </p> </div> </th> ))} </tr> </thead> <tbody> {FEATURES.map((feature) => ( <tr key={feature.name}> <td className={cn( "relative z-0 px-3 py-2.5 text-xs tracking-wide text-muted-foreground", rowRule, )} > <span className="relative z-20">{feature.name}</span> </td> {PLANS.map((plan) => ( <td key={plan.key} className={cn( "relative z-0 px-3 py-2.5 text-center text-xs tracking-wide", plan.featured ? cn( "bg-primary text-primary-foreground", featuredRowRule, ) : cn("text-foreground", rowRule), )} > <span className="relative z-20">{feature[plan.key]}</span> </td> ))} </tr> ))} <tr> <td className={cn("relative z-0 px-3 py-3", rowRule)} /> {PLANS.map((plan) => ( <td key={plan.key} className={cn( "relative z-0 px-3 py-3 text-center", plan.featured ? cn( "rounded-b-lg bg-primary text-primary-foreground", featuredRowRule, ) : rowRule, )} > <div className="relative z-20 flex justify-center"> <Button type="button" size="sm" className="w-full max-w-[9rem]" variant={plan.featured ? "secondary" : "outline"} > {plan.cta} </Button> </div> </td> ))} </tr> </tbody> </table> </div> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add pricing-03Usage
import { Pricing03 } from "@/components/blocks/pricing/pricing-03"<Pricing03 />