# Pricing 9

A shadcn/ui block from the [@diarmuradi](https://diarmuradi.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/diarmuradi/pricing-9).

- Page, with a live preview: https://shadcn.exchange/r/diarmuradi/pricing-9
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/diarmuradi/pricing-9-light-bbc8601bbf4b50ed.png
- Registry item: https://diarmuradi.com/r/pricing-9.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://diarmuradi.com/r/pricing-9.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `cn`, `lucide-react`, `motion`
- Registry items: `https://diarmuradi.com/r/styles/base-nova/badge.json`, `https://diarmuradi.com/r/styles/base-nova/button.json`, `https://diarmuradi.com/r/styles/base-nova/fancy-button.json`, `https://diarmuradi.com/r/styles/base-nova/switch.json`

## Files

### `pricing.tsx`

```tsx
"use client"

import { useState } from "react"
import { cn } from "cn"
import { AnimatePresence, motion, type Variants } from "motion/react"

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Switch } from "@/components/ui/switch"
import { FancyButton } from "@/components/ui/fancy-button"
import { ArrowUpRightIcon, ChartLineIcon, CheckIcon, CodeIcon, DatabaseIcon, LockIcon, RepeatIcon, SettingsIcon } from 'lucide-react'

const animVariant: Variants = {
  initial: { opacity: 0, y: 10, filter: "blur(4px)", scale: 0.98 },
  animate: (i: number) => ({
    opacity: 1,
    y: 0,
    filter: "blur(0px)",
    scale: 1,
    transition: {
      delay: i * 0.03,
      type: "spring",
      damping: 22,
      stiffness: 280,
    },
  }),
  exit: {
    opacity: 0,
    y: -10,
    filter: "blur(4px)",
    scale: 0.98,
    transition: { duration: 0.14 },
  },
}

type FeatureToggle = {
  id: string
  label: string
  icon?: React.ReactNode
  price: number
  enabled: boolean
}

const defaultFeatures: FeatureToggle[] = [
  {
    id: "analytics",
    label: "Analytics engine",
    icon: (
      <ChartLineIcon  className="size-4" />
    ),
    price: 15,
    enabled: true,
  },
  {
    id: "api",
    label: "API gateway",
    icon: (
      <CodeIcon  className="size-4" />
    ),
    price: 20,
    enabled: true,
  },
  {
    id: "storage",
    label: "Cloud storage (100 GB)",
    icon: (
      <DatabaseIcon  className="size-4" />
    ),
    price: 10,
    enabled: false,
  },
  {
    id: "automation",
    label: "Workflow automation",
    icon: (
      <RepeatIcon  className="size-4" />
    ),
    price: 25,
    enabled: false,
  },
  {
    id: "security",
    label: "Advanced security",
    icon: (
      <LockIcon  className="size-4" />
    ),
    price: 30,
    enabled: false,
  },
  {
    id: "custom",
    label: "Custom integrations",
    icon: (
      <SettingsIcon  className="size-4" />
    ),
    price: 20,
    enabled: false,
  },
]

const includedFeatures = [
  "Unlimited team members",
  "Core dashboard access",
  "Email support",
  "5 GB base storage",
]

const basePrice = 29

export function Pricing() {
  const [features, setFeatures] = useState<FeatureToggle[]>(defaultFeatures)

  const totalPrice =
    basePrice +
    features.filter((f) => f.enabled).reduce((sum, f) => sum + f.price, 0)

  const priceChars = totalPrice.toString().split("")

  const toggleFeature = (id: string) => {
    setFeatures((prev) =>
      prev.map((f) => (f.id === id ? { ...f, enabled: !f.enabled } : f))
    )
  }

  return (
    <section aria-label="Pricing" className="mx-auto w-full max-w-4xl">
      <div className="flex flex-col items-center gap-8">
        <div className="flex flex-col items-center gap-4 text-center">
          <Badge variant="secondary" className="w-fit">
            Build your plan
          </Badge>
          <h2 className="text-4xl font-bold tracking-tight text-foreground sm:text-5xl">
            Only pay for what you need
          </h2>
          <p className="max-w-2xl text-lg text-muted-foreground">
            Start with a base plan and add modules as your infrastructure grows.
            Full flexibility, zero waste.
          </p>
        </div>

        <div className="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
          <div className="flex flex-col gap-6 rounded-4xl bg-card p-8 shadow-elevated-lg">
            <div className="flex flex-col gap-2">
              <h3 className="text-lg font-medium text-foreground">
                Add-on modules
              </h3>
              <p className="text-sm text-muted-foreground">
                Toggle the features you need. Price updates in real-time.
              </p>
            </div>

            <div className="flex flex-col gap-4">
              {features.map((feature) => (
                <div
                  key={feature.id}
                  className="flex items-center justify-between gap-4 rounded-lg p-2"
                >
                  <Button
                    type="button"
                    variant="ghost"
                    onClick={() => toggleFeature(feature.id)}
                    className="h-auto flex-1 justify-start rounded-lg p-0 hover:bg-transparent"
                  >
                    <div className="flex items-center gap-3 text-left">
                      <div
                        className={cn(
                          "flex size-9 items-center justify-center rounded-full transition-colors",
                          feature.enabled
                            ? "bg-primary text-primary-foreground"
                            : "bg-muted text-muted-foreground"
                        )}
                      >
                        {feature.icon}
                      </div>
                      <div className="flex flex-col">
                        <span className="text-sm font-medium text-foreground">
                          {feature.label}
                        </span>
                        <span className="text-start text-xs text-muted-foreground">
                          +${feature.price}/mo
                        </span>
                      </div>
                    </div>
                  </Button>
                  <Switch
                    aria-label={feature.label}
                    checked={feature.enabled}
                    onCheckedChange={() => toggleFeature(feature.id)}
                  />
                </div>
              ))}
            </div>
          </div>

          <div className="flex flex-col gap-6 rounded-4xl bg-muted p-8">
            <div className="flex flex-col gap-2">
              <h3 className="text-xl font-medium text-foreground">Your plan</h3>
              <p className="text-sm text-muted-foreground">
                Base plan + {features.filter((f) => f.enabled).length} add-ons
                selected
              </p>
            </div>

            <div className="flex flex-col gap-1">
              <div className="flex items-baseline gap-1">
                <span className="text-7xl font-semibold tracking-tight text-foreground">
                  $
                </span>
                <AnimatePresence mode="popLayout">
                  {priceChars.map((char, idx) => (
                    <motion.span
                      key={`${totalPrice}-${char}-${idx}`}
                      variants={animVariant}
                      initial="initial"
                      animate="animate"
                      exit="exit"
                      custom={idx}
                      className="inline-block text-7xl font-semibold tracking-tight text-foreground"
                    >
                      {char}
                    </motion.span>
                  ))}
                </AnimatePresence>
                <span key="period" className="text-xl text-muted-foreground">
                  /month
                </span>
              </div>
              <p className="text-sm text-muted-foreground">
                Base: ${basePrice} + Add-ons: ${totalPrice - basePrice}
              </p>
            </div>

            <FancyButton size="lg" className="w-full">
              Start free trial
              <ArrowUpRightIcon  data-icon="inline-end" />
            </FancyButton>

            <div className="flex flex-col gap-3">
              <p className="text-sm font-medium text-foreground">
                Always included
              </p>
              <ul className="flex flex-col gap-3">
                {includedFeatures.map((feature) => (
                  <li key={feature} className="flex items-start gap-3">
                    <div className="mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full bg-primary">
                      <CheckIcon  className="size-3 text-primary-foreground" />
                    </div>
                    <span className="text-sm text-muted-foreground">
                      {feature}
                    </span>
                  </li>
                ))}
              </ul>
            </div>
          </div>
        </div>
      </div>
    </section>
  )
}
```
