# Pricing 10

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

- Page, with a live preview: https://shadcn.exchange/r/diarmuradi/pricing-10
- Screenshot: https://shadcn.exchange/shot/diarmuradi/pricing-10/light.png
- Registry item: https://diarmuradi.com/r/pricing-10.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/diarmuradi/pricing-10.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: `lucide-react`, `motion`
- Registry items: `https://diarmuradi.com/r/styles/base-nova/badge.json`, `https://diarmuradi.com/r/styles/base-nova/fancy-button.json`, `https://diarmuradi.com/r/styles/base-nova/separator.json`, `https://diarmuradi.com/r/styles/base-nova/slider.json`

## Files

### `pricing.tsx`

```tsx
"use client"

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

import { Badge } from "@/components/ui/badge"
import { Separator } from "@/components/ui/separator"
import { Slider } from "@/components/ui/slider"
import { FancyButton } from "@/components/ui/fancy-button"
import { ArrowUpRightIcon, CheckIcon } from 'lucide-react'

const animVariant: Variants = {
  initial: { opacity: 0, y: 24, scale: 0.7 },
  animate: (i: number) => ({
    opacity: 1,
    y: 0,
    scale: 1,
    transition: {
      delay: i * 0.04,
      type: "spring",
      damping: 12,
      stiffness: 400,
      mass: 0.8,
    },
  }),
  exit: {
    opacity: 0,
    y: -16,
    scale: 0.85,
    transition: { duration: 0.12 },
  },
}

type PriceTier = {
  maxVolume: number
  label: string
  price: number
}

const priceTiers: PriceTier[] = [
  { maxVolume: 10000, label: "10K", price: 49 },
  { maxVolume: 50000, label: "50K", price: 149 },
  { maxVolume: 200000, label: "200K", price: 399 },
  { maxVolume: 500000, label: "500K", price: 699 },
  { maxVolume: 1000000, label: "1M", price: 899 },
]

const features = [
  "Unlimited API endpoints",
  "Real-time event streaming",
  "Global edge deployment",
  "Custom rate limiting",
  "Advanced error tracking",
  "Dedicated support channel",
]

export function Pricing() {
  const [volume, setVolume] = useState(50000)
  const volumeLabelId = useId()
  const shouldReduceMotion = useReducedMotion()

  const currentTier =
    priceTiers.find((tier) => volume <= tier.maxVolume) ??
    priceTiers[priceTiers.length - 1]!
  const priceChars = currentTier.price.toString().split("")

  return (
    <section aria-label="Pricing" className="mx-auto w-full max-w-5xl">
      <div className="flex flex-col items-center gap-8">
        <div className="flex flex-col items-center gap-4 text-center">
          <Badge variant="outline" className="w-fit">
            Volume pricing
          </Badge>
          <h2 className="text-4xl font-bold tracking-tight text-foreground sm:text-5xl">
            Scale without limits
          </h2>
          <p className="max-w-2xl text-lg text-muted-foreground">
            Pricing that adapts to your traffic. Slide to estimate your monthly
            cost based on API requests.
          </p>
        </div>

        <div className="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
          <div className="flex flex-col gap-8 rounded-4xl bg-muted p-8">
            <div className="flex flex-col gap-4">
              <div className="flex items-center justify-between gap-3">
                <h3
                  id={volumeLabelId}
                  className="text-lg font-medium text-foreground"
                >
                  Monthly API requests
                </h3>
                <Badge variant="secondary" className="shrink-0">
                  {currentTier.label}
                </Badge>
              </div>
              <Slider
                aria-labelledby={volumeLabelId}
                value={[volume]}
                onValueChange={(value) =>
                  setVolume(Array.isArray(value) ? (value[0] ?? 1000) : value)
                }
                min={1000}
                max={1000000}
                step={1000}
                className="cursor-grab active:cursor-grabbing **:data-[slot=slider-thumb]:h-6.5 **:data-[slot=slider-thumb]:w-3 **:data-[slot=slider-thumb]:border-3 **:data-[slot=slider-thumb]:border-muted **:data-[slot=slider-thumb]:bg-primary **:data-[slot=slider-thumb]:ring-0 **:data-[slot=slider-thumb]:focus-within:ring-3 **:data-[slot=slider-track]:h-2 **:data-[slot=slider-track]:bg-input/60"
              />
              <div className="flex items-center justify-between text-xs text-muted-foreground">
                <span>1K</span>
                <span className="text-sm font-medium text-foreground">
                  {volume.toLocaleString("en-US", {
                    notation: "compact",
                    maximumFractionDigits: 0,
                  })}{" "}
                  requests/mo
                </span>
                <span>1M</span>
              </div>
            </div>

            <Separator />

            <div className="flex flex-col items-center gap-3 text-center">
              <div className="flex items-baseline gap-1">
                <span className="text-7xl font-semibold tracking-tight text-foreground">
                  $
                </span>
                <AnimatePresence initial={false} mode="popLayout">
                  {priceChars.map((char, idx) => (
                    <motion.span
                      key={`${currentTier.price}-${char}-${idx}`}
                      variants={animVariant}
                      initial={shouldReduceMotion ? false : "initial"}
                      animate="animate"
                      exit={shouldReduceMotion ? undefined : "exit"}
                      custom={idx}
                      className="inline-block text-7xl font-semibold tracking-tight text-foreground"
                    >
                      {char}
                    </motion.span>
                  ))}
                </AnimatePresence>
                <span className="text-xl text-muted-foreground">/month</span>
              </div>
            </div>

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

          <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-xl font-medium text-foreground">
                Every plan includes
              </h3>
              <p className="text-sm leading-relaxed text-muted-foreground">
                No matter your volume, you get full access to our complete
                platform with enterprise-grade reliability.
              </p>
            </div>

            <ul className="flex flex-col gap-4">
              {features.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-base text-muted-foreground">
                    {feature}
                  </span>
                </li>
              ))}
            </ul>
          </div>
        </div>
      </div>
    </section>
  )
}
```
