# Pricing 12

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-12).

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

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/diarmuradi/pricing-12.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`, `motion`
- Registry items: `https://diarmuradi.com/r/styles/base-nova/fancy-button.json`, `https://diarmuradi.com/r/styles/base-nova/field.json`, `https://diarmuradi.com/r/styles/base-nova/input-group.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 { cn } from "cn"
import {
  AnimatePresence,
  motion,
  useReducedMotion,
  type Variants,
} from "motion/react"

import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput,
  InputGroupText,
} from "@/components/ui/input-group"
import { Separator } from "@/components/ui/separator"
import { Slider } from "@/components/ui/slider"
import { FancyButton } from "@/components/ui/fancy-button"

const animVariant: Variants = {
  hidden: { opacity: 0, y: 10, filter: "blur(4px)", scale: 0.98 },
  visible: (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 },
  },
}

export function Pricing() {
  const [weeklyReports, setWeeklyReports] = useState(10)
  const [costPerReport, setCostPerReport] = useState(150)
  const reportsLabelId = useId()
  const costInputId = useId()
  const shouldReduceMotion = useReducedMotion()
  const maxWeeklyReports = 20
  const reportTicks = Array.from(
    { length: maxWeeklyReports + 1 },
    (_, tick) => tick
  )

  const monthlyReports = weeklyReports * 4
  const monthlyValueSaved = monthlyReports * costPerReport
  const platformCost = 299
  const totalRoi = Math.max(0, monthlyValueSaved - platformCost)

  const roiChars = totalRoi.toLocaleString("en-US").split("")

  return (
    <section
      aria-label="Pricing"
      className="mx-auto flex w-full max-w-5xl flex-col gap-10"
    >
      <h2 className="max-w-xl text-4xl font-semibold tracking-tight text-balance text-foreground sm:text-5xl">
        See what you save
      </h2>

      <div className="flex w-full flex-col gap-2 rounded-4xl bg-card p-1 shadow-elevated-lg lg:flex-row">
        <div className="flex min-w-0 flex-1 flex-col gap-10 p-6 sm:p-8 lg:p-10">
          <div className="flex flex-col gap-10">
            <p
              id={reportsLabelId}
              className="text-lg leading-relaxed text-muted-foreground"
            >
              How many complex data reports is your team compiling manually
              every single week?
            </p>

            <div className="flex flex-col gap-8">
              <div className="flex flex-wrap items-center justify-center gap-2 text-4xl font-bold tracking-tight text-foreground sm:text-5xl">
                <span>{weeklyReports}</span>
                <span>reports</span>
              </div>
              <div className="grid w-full gap-4">
                <Slider
                  aria-labelledby={reportsLabelId}
                  value={[weeklyReports]}
                  onValueChange={(value) =>
                    setWeeklyReports(
                      Array.isArray(value) ? (value[0] ?? 0) : value
                    )
                  }
                  max={maxWeeklyReports}
                  min={0}
                  step={1}
                  className="cursor-grab active:cursor-grabbing **:data-[slot=slider-thumb]:size-6 **:data-[slot=slider-thumb]:border-4 **:data-[slot=slider-thumb]:border-card **: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.5 **:data-[slot=slider-track]:bg-input/60"
                />
                <div
                  aria-hidden="true"
                  className="flex w-full items-start justify-between px-3 text-xs font-medium text-muted-foreground"
                >
                  {reportTicks.map((tick) => (
                    <span
                      key={tick}
                      className="flex w-0 flex-col items-center gap-2"
                    >
                      <span
                        className={cn(
                          "w-px bg-muted-foreground/30",
                          tick % 5 === 0 ? "h-2" : "h-1"
                        )}
                      />
                      {tick % 5 === 0 && <span>{tick}</span>}
                    </span>
                  ))}
                </div>
              </div>
            </div>
          </div>

          <Separator className="bg-border/50" />

          <FieldGroup>
            <Field orientation="responsive" className="gap-3">
              <FieldLabel htmlFor={costInputId} className="text-base">
                Average cost per report
              </FieldLabel>
              <InputGroup className="h-11 bg-transparent @md/field-group:w-40 @md/field-group:shrink-0">
                <InputGroupAddon>
                  <InputGroupText>$</InputGroupText>
                </InputGroupAddon>
                <InputGroupInput
                  id={costInputId}
                  type="number"
                  value={costPerReport}
                  onChange={(event) =>
                    setCostPerReport(
                      Math.max(0, event.target.valueAsNumber || 0)
                    )
                  }
                  min={0}
                  className="text-base font-semibold tabular-nums"
                />
              </InputGroup>
            </Field>
          </FieldGroup>
        </div>

        <div className="flex w-full flex-col items-center justify-between gap-8 rounded-3xl bg-muted p-6 sm:p-8 lg:w-sm lg:shrink-0 lg:p-10">
          <div className="flex w-full flex-col items-center gap-2 text-center">
            <h3 className="font-medium tracking-tight text-foreground">
              Automated Monthly ROI
            </h3>
            <div className="mt-2 max-w-full text-5xl leading-none font-bold tracking-tight break-all text-foreground sm:text-7xl">
              <span>$</span>
              <AnimatePresence initial={false} mode="popLayout">
                {roiChars.map((char, idx) => (
                  <motion.span
                    key={`${totalRoi}-${idx}`}
                    variants={animVariant}
                    initial={shouldReduceMotion ? false : "hidden"}
                    animate="visible"
                    exit={shouldReduceMotion ? undefined : "exit"}
                    custom={idx}
                    className="inline-block"
                  >
                    {char}
                  </motion.span>
                ))}
              </AnimatePresence>
            </div>
            <p className="mt-4 text-sm text-muted-foreground">
              Net savings with a DataSync enterprise plan
            </p>
            <FancyButton
              size="lg"
              className="mt-6 w-full text-base font-medium"
            >
              Start your free trial
            </FancyButton>
          </div>

          <div className="flex w-full flex-col gap-3 text-sm">
            <p className="text-xs font-medium tracking-wider text-muted-foreground uppercase">
              Breakdown
            </p>
            {[
              { label: "Reports automated monthly", value: monthlyReports },
              {
                label: "Capital preserved",
                value: `$${monthlyValueSaved.toLocaleString("en-US")}`,
              },
              { label: "DataSync platform fee", value: `$${platformCost}` },
            ].map(({ label, value }) => (
              <div
                key={label}
                className="flex items-start justify-between gap-4"
              >
                <span className="text-muted-foreground">{label}</span>
                <span className="min-w-0 text-right font-medium break-all text-foreground">
                  {value}
                </span>
              </div>
            ))}
            <Separator className="my-1 bg-border/50" />
            <div className="flex items-start justify-between gap-4 font-semibold">
              <span className="text-foreground">Total monthly ROI</span>
              <span className="min-w-0 text-right break-all text-foreground">
                ${totalRoi.toLocaleString("en-US")}
              </span>
            </div>
          </div>
        </div>
      </div>
    </section>
  )
}
```
