# Pricing 7

> Team seat slider with animated total — $147 base plus per-seat pricing with tabular-nums price handoff.

A shadcn/ui block from the [@nusaiba](https://nusaiba.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/nusaiba/pricing-7).

- Page, with a live preview: https://shadcn.exchange/r/nusaiba/pricing-7
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/nusaiba/pricing-7-light-74e1b4b7ff40ac96.png
- Registry item: https://nusaiba.dev/r/base-nova/pricing-7.json
- Categories: pricing
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://nusaiba.dev/r/base-nova/pricing-7.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: `motion`
- Registry items: `@nusaiba/foundation`, `button`

## Files

### `registry/blocks/pricing/7/pricing-section.tsx`

```tsx
"use client";

import { useMemo, useState } from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { Button } from "@/components/ui/button";
import { defaultSpring, motionViewport } from "@/lib/motion-tokens";
import { cn } from "@/lib/utils";
import { SectionShell, ContentRail } from "@/components/layout-contract";

const BASE_PRICE = 147;
const SEAT_PRICE = 39;
const MIN_SEATS = 1;
const MAX_SEATS = 20;

function formatPrice(amount: number) {
	return `$${amount.toLocaleString("en-US")}`;
}

export function PricingSeatsSection() {
	const reduceMotion = useReducedMotion();
	const [seats, setSeats] = useState(3);

	const total = useMemo(
		() => BASE_PRICE + Math.max(0, seats - 1) * SEAT_PRICE,
		[seats],
	);

	return (
		<SectionShell spacingMode="section" className="bg-background">
			<ContentRail maxWidth="max-w-2xl" className="space-y-8 md:space-y-10">
				<div className="max-w-xl space-y-2">
					<p className="font-medium text-primary text-xs uppercase tracking-[0.22em]">
						Team
					</p>
					<h2 className="text-balance font-medium text-2xl tracking-tight md:text-4xl">
						Scale by seats
					</h2>
					<p className="text-pretty text-muted-foreground text-sm md:text-base">
						Pro starts at $147 once — add seats at $39 each for shared registry access
						across your team.
					</p>
				</div>

				<motion.div
					className="space-y-8 rounded-[var(--radius-md)] border border-border bg-background p-6 shadow-[0_1px_2px_rgba(0,0,0,0.04)] md:p-8 dark:shadow-[0_1px_2px_rgba(0,0,0,0.2)]"
					initial={reduceMotion ? false : { opacity: 0, y: 12, filter: "blur(4px)" }}
					transition={defaultSpring}
					viewport={motionViewport}
					whileInView={reduceMotion ? undefined : { opacity: 1, y: 0, filter: "blur(0px)" }}
				>
					<div className="flex flex-wrap items-end justify-between gap-4">
						<div>
							<p className="font-mono text-[10px] text-muted-foreground uppercase tracking-[0.14em]">
								Total
							</p>
							<AnimatePresence initial={false} mode="popLayout">
								<motion.p
									animate={reduceMotion ? undefined : { opacity: 1, y: 0, filter: "blur(0px)" }}
									className="font-medium text-4xl tabular-nums tracking-tight md:text-5xl"
									exit={
										reduceMotion
											? undefined
											: {
													opacity: 0,
													y: -6,
													filter: "blur(4px)",
													transition: { duration: 0.15, ease: "easeIn" },
												}
									}
									initial={reduceMotion ? false : { opacity: 0, y: 8, filter: "blur(4px)" }}
									key={total}
									transition={{ type: "spring", duration: 0.3, bounce: 0 }}
								>
									{formatPrice(total)}
								</motion.p>
							</AnimatePresence>
							<p className="mt-1 text-muted-foreground text-sm">once · includes Pro catalog</p>
						</div>
						<div className="text-right">
							<p className="font-medium text-2xl tabular-nums">{seats}</p>
							<p className="text-muted-foreground text-xs">
								seat{seats === 1 ? "" : "s"}
							</p>
						</div>
					</div>

					<div className="space-y-3">
						<label className="font-medium text-sm" htmlFor="pricing-seats">
							Team seats
						</label>
						<input
							aria-valuemax={MAX_SEATS}
							aria-valuemin={MIN_SEATS}
							aria-valuenow={seats}
							className={cn(
								"h-2 w-full cursor-pointer appearance-none rounded-full bg-muted",
								"[&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-primary [&::-webkit-slider-thumb]:shadow-[0_1px_2px_rgba(0,0,0,0.2)]",
								"[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-primary",
							)}
							id="pricing-seats"
							max={MAX_SEATS}
							min={MIN_SEATS}
							onChange={(event) => setSeats(Number(event.target.value))}
							type="range"
							value={seats}
						/>
						<div className="flex justify-between font-mono text-[10px] text-muted-foreground uppercase tracking-[0.12em]">
							<span>{MIN_SEATS} seat</span>
							<span>{MAX_SEATS} seats</span>
						</div>
					</div>

					<ul className="space-y-2 text-pretty text-muted-foreground text-sm">
						<li>
							<span className="text-foreground">{formatPrice(BASE_PRICE)}</span> base Pro
							license
						</li>
						<li>
							<span className="text-foreground">+{formatPrice(SEAT_PRICE)}</span> per
							additional seat
						</li>
					</ul>

					<Button className="w-full active:scale-[0.96] sm:w-auto">
						Get team access
					</Button>
				</motion.div>
			</ContentRail>
		</SectionShell>
	);
}
```
