A design studio's three ways to work together, set in an editorial serif with tighter corners (`radius={6}`), a wider `gap` and warm `--dock-border` lines. `formatPrice` writes prices in thousands, the Sprint sets its own `/sprint` period, and Quarterly billing rolls the retainers down.
@keyframeui
registry/demos/pricing-dock-studio-demo.tsx
"use client";
import * as React from "react";
import { PricingDock, type PricingDockGroup, type PricingDockPlan } from "@/components/ui/pricing-dock";
const plans: PricingDockPlan[] = [
{
id: "sprint",
name: "Sprint",
price: 8,
period: "/sprint",
caption: "Two weeks, fixed scope",
pitch: "A launch page, deck or rebrand in two weeks.",
highlights: ["One request at a time", "Delivered in two weeks", "Two rounds of revisions", "Source files included"],
cta: { label: "Book a call", href: "#" },
},
{
id: "retainer",
name: "Retainer",
price: { monthly: 12, quarterly: 11 },
caption: { monthly: "Pause or cancel any month", quarterly: "Billed every three months" },
pitch: "Senior designers shipping weekly, no hiring.",
highlights: ["Two active requests", "48-hour turnaround", "A dedicated lead designer", "Shared Slack channel"],
featured: true,
badge: "Most chosen",
cta: { label: "Book a call", href: "#" },
},
{
id: "partner",
name: "Partner",
price: { monthly: 20, quarterly: 18 },
caption: { monthly: "Three-month minimum", quarterly: "Billed every three months" },
pitch: "Brand, product and web, run like your in-house team.",
highlights: ["Three active requests", "Same-day turnaround on small asks", "Design lead and design engineer", "Quarterly brand strategy"],
cta: { label: "Book a call", href: "#" },
},
];
const groups: PricingDockGroup[] = [
{
label: "Capacity",
rows: [
{
feature: "Active requests",
hint: "How many briefs we work on at once. Queue as many as you like; the next starts when one ships.",
values: { sprint: "1", retainer: "2", partner: "3" },
},
{ feature: "Turnaround", values: { sprint: "2 weeks", retainer: "48 hours", partner: "Same day" } },
{ feature: "Revisions", values: { sprint: "2 rounds", retainer: "Unlimited", partner: "Unlimited" } },
{ feature: "Pause any time", values: { sprint: false, retainer: true, partner: true } },
],
},
{
label: "Team",
rows: [
{ feature: "Dedicated designer", values: { sprint: false, retainer: true, partner: true } },
{ feature: "Design engineer", values: { sprint: false, retainer: false, partner: true } },
{ feature: "Creative direction", values: { sprint: false, retainer: "Monthly", partner: "Weekly" } },
{ feature: "Slack channel", values: { sprint: false, retainer: true, partner: true } },
],
},
{
label: "What we make",
rows: [
{ feature: "Brand identity", values: { sprint: "Refresh", retainer: true, partner: true } },
{ feature: "Websites and landing pages", values: { sprint: true, retainer: true, partner: true } },
{
feature: "Framer or Webflow build",
hint: "We hand over a live site your team can edit, not just the design files.",
values: { sprint: false, retainer: true, partner: true },
},
{ feature: "Motion and video", values: { sprint: false, retainer: "Add-on", partner: true } },
{ feature: "Product UI", values: { sprint: false, retainer: true, partner: true } },
],
},
{
label: "Terms",
rows: [
{ feature: "Minimum term", values: { sprint: "One sprint", retainer: "One month", partner: "Three months" } },
{ feature: "You own everything", values: { sprint: true, retainer: true, partner: true } },
],
},
];
export function PricingDockStudioDemo() {
const scrollRef = React.useRef<HTMLDivElement>(null);
return (
<div className="relative isolate w-full overflow-hidden rounded-xl border border-stone-300/70 bg-[#f4efe7] font-serif text-stone-900 dark:border-stone-800 dark:bg-stone-950 dark:text-stone-100">
<div ref={scrollRef} className="h-[var(--demo-height,44rem)] overflow-y-auto overscroll-contain">
<div className="mx-auto max-w-5xl px-4 sm:px-6">
<header className="flex flex-col items-center pt-16 pb-12 text-center sm:pt-24">
<p className="font-sans text-[11px] tracking-[0.2em] text-[#a8492a] uppercase dark:text-[#e2875f]">
Atelier North · Work with us
</p>
<h2 className="mt-4 max-w-lg text-4xl/[1.1] tracking-tight text-balance sm:text-5xl/[1.05]">
A senior design team, <em className="text-[#a8492a] dark:text-[#e2875f]">on call</em>
</h2>
<p className="mt-4 max-w-md font-sans text-sm/6 text-pretty text-stone-600 dark:text-stone-400">
Three ways to work together. Every plan gets the same people; you choose how much of their week.
</p>
</header>
<PricingDock
containerRef={scrollRef}
plans={plans}
groups={groups}
billing={[
{ id: "monthly", label: "Monthly" },
{ id: "quarterly", label: "Quarterly", note: "−8%" },
]}
formatPrice={(amount) => `$${amount}k`}
intro="Not sure which fits? Most studios start with a Sprint and move to a Retainer once the first project ships."
compareLabel="See everything included"
radius={6}
gap={16}
className="[--dock-border:#e2d8c8] dark:[--dock-border:var(--color-stone-800)] [--dock-accent:#a8492a] [--dock-accent-foreground:#fbf8f3] [--dock-page:#f4efe7] [--dock-surface:#fbf8f3] dark:[--dock-accent:#e2875f] dark:[--dock-accent-foreground:#1c1917] dark:[--dock-page:var(--color-stone-950)] dark:[--dock-surface:var(--color-stone-900)] [&_[role=cell]]:font-sans [&_[role=cell]]:text-[13px] [&_[role=rowheader]]:text-[15px]"
/>
<footer className="flex flex-col items-center py-28 text-center">
<h3 className="text-3xl tracking-tight">
Let's talk about <em>your</em> next launch
</h3>
<p className="mt-3 max-w-sm font-sans text-sm/6 text-pretty text-stone-600 dark:text-stone-400">
Twenty minutes with a founder, no slides. We'll tell you honestly if we're the right fit.
</p>
<a
href="#"
className="mt-6 rounded-full bg-[#a8492a] px-5 py-2.5 font-sans text-sm font-medium text-[#fbf8f3] transition-colors hover:bg-[#93401f] dark:bg-[#e2875f] dark:text-stone-900"
>
Book a call
</a>
</footer>
</div>
</div>
</div>
);
}
Live preview, examples and props: https://keyframeui.com/components/pricing-dock#pricing-dock-studio-demo



























