Skip to content

Membership Card

Single plan pricing as a membership card: spring 3D tilt, flips over, with honest included and excluded lists.

  • Pricing
  • Healthcare
  • React only · 0 deps
  • 1 file
Full screen

Browser support · All evergreen browsers (3D transforms with backface-visibility). Pointer tilt is skipped with reduced motion.

Install. One command, or copy the file.

$npx shadcn@latest add https://freedesignmd.com/r/membership-card.json
  • Byte-identical to the preview
  • No Tailwind or config needed
  • SSR-safe · keyboard accessible
  • Respects reduced motion & transparency
components/pricing/membership-card.tsx
1/**
2 * MembershipCard, a single-plan pricing section for a premium clinic
3 * membership, presented as the physical card members carry. The card tilts
4 * in 3D toward the pointer (spring physics) with a light sheen that follows
5 * it, and flips to its back (care-team line, signature strip) on click or
6 * Enter. Beside it: the price, what is included and, just as clearly, what is
7 * not.
8 *
9 * Props: brand, member ({ name, number, since, clinic }), price
10 * ({ monthly, yearly, currency }), included / excluded ([title, detail][]),
11 * title, lede, cta, backLines.
12 * CSS vars: --fd-mc-bg, --fd-mc-ink, --fd-mc-card, --fd-mc-foil.
13 *
14 * Browser support: all evergreen browsers (3D transforms, backface-visibility).
15 * Accessibility: the card is a real <button> with aria-pressed reflecting the
16 * flip; both faces are readable text (the hidden face is aria-hidden). Lists
17 * use <ul> with headings.
18 * Reduced motion: no tilt or sheen; the flip is instant.
19 */
20import { useEffect, useRef, useState } from "react";
21
22export interface MembershipCardProps {
23 brand?: string;
24 member?: { name: string; number: string; since: string; clinic: string };
25 price?: { monthly: number; yearly: number; currency: string };
26 title?: string;
27 lede?: string;
28 included?: [string, string][];
29 excluded?: [string, string][];
30 cta?: { label: string; href: string };
31 backLines?: [string, string][];
32 className?: string;
33}
34
35const INCLUDED: [string, string][] = [
36 ["Unlimited GP appointments", "Same or next day, 30 minutes each, in person or video."],
37 ["Annual health assessment", "90 minutes with your GP, bloods covering 42 markers, results explained in person."],
38 ["A direct line to your care team", "WhatsApp or phone, 8am to 8pm, seven days. Median reply: 11 minutes."],
39 ["Prescriptions and referrals", "Issued the same day. Referral letters within 24 hours."],
40 ["Two physiotherapy sessions a year", "45 minutes each at our Marylebone clinic."],
41];
42
43const EXCLUDED: [string, string][] = [
44 ["Emergency care", "Chest pain, a bad fall, anything urgent: call 999 or go to A&E."],
45 ["Specialist and hospital fees", "We refer you and chase it. The consultant bills you or your insurer."],
46 ["The cost of medication", "Your prescription is free; the pharmacy charges for what's on it."],
47 ["Dental, optical and fertility care", "Not something we do well enough to include."],
48];
49
50const BACK: [string, string][] = [
51 ["Care team", "+44 20 7946 0321"],
52 ["WhatsApp", "8am to 8pm, 7 days"],
53 ["Clinics", "Marylebone · Islington · Clapham"],
54];
55
56const serif = `"Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif`;
57
58export function MembershipCard({
59 brand = "Marlow House",
60 member = { name: "Priya Raman", number: "MH 0419 2286", since: "11 / 2026", clinic: "Marylebone" },
61 price = { monthly: 115, yearly: 1240, currency: "£" },
62 title = "One membership. A GP who knows your name by the second visit.",
63 lede = "No tiers, no add-ons at the till. Join for yourself or add a partner at the same price. Cancel any month after the first three.",
64 included = INCLUDED,
65 excluded = EXCLUDED,
66 cta = { label: "Become a member", href: "#join" },
67 backLines = BACK,
68 className,
69}: MembershipCardProps) {
70 const stage = useRef<HTMLDivElement>(null);
71 const tilt = useRef<HTMLDivElement>(null);
72 const [flipped, setFlipped] = useState(false);
73
74 useEffect(() => {
75 const st = stage.current;
76 const el = tilt.current;
77 if (!st || !el) return;
78 if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
79 const s = { x: 0, y: 0, vx: 0, vy: 0, tx: 0, ty: 0, mx: 50, my: 30 };
80 let raf = 0;
81 let last = 0;
82 const K = 380, C = 30;
83 const tick = (now: number) => {
84 const dt = Math.min((now - last) / 1000, 1 / 30);
85 last = now;
86 for (const k of ["x", "y"] as const) {
87 const t = k === "x" ? s.tx : s.ty;
88 const v = k === "x" ? "vx" : "vy";
89 const a = K * (t - s[k]) - C * s[v];
90 s[v] += a * dt;
91 s[k] += s[v] * dt;
92 }
93 el.style.transform = `rotateX(${s.y.toFixed(2)}deg) rotateY(${s.x.toFixed(2)}deg)`;
94 el.style.setProperty("--mx", `${s.mx}%`);
95 el.style.setProperty("--my", `${s.my}%`);
96 const still = Math.abs(s.tx - s.x) < 0.01 && Math.abs(s.ty - s.y) < 0.01 && Math.abs(s.vx) < 0.01 && Math.abs(s.vy) < 0.01;
97 raf = still ? 0 : requestAnimationFrame(tick);
98 };
99 const kick = () => {
100 if (!raf) {
101 last = performance.now();
102 raf = requestAnimationFrame(tick);
103 }
104 };
105 const move = (e: PointerEvent) => {
106 const r = st.getBoundingClientRect();
107 const px = (e.clientX - r.left) / r.width;
108 const py = (e.clientY - r.top) / r.height;
109 s.tx = (px - 0.5) * 22;
110 s.ty = -(py - 0.5) * 18;
111 s.mx = px * 100;
112 s.my = py * 100;
113 el.dataset.hover = "";
114 kick();
115 };
116 const leave = () => {
117 s.tx = 0;
118 s.ty = 0;
119 s.mx = 50;
120 s.my = 30;
121 delete el.dataset.hover;
122 kick();
123 };
124 st.addEventListener("pointermove", move);
125 st.addEventListener("pointerleave", leave);
126 return () => {
127 cancelAnimationFrame(raf);
128 st.removeEventListener("pointermove", move);
129 st.removeEventListener("pointerleave", leave);
130 };
131 }, []);
132
133 const saving = price.monthly * 12 - price.yearly;
134
135 return (
136 <section className={`fd-mc${className ? " " + className : ""}`} aria-label={`${brand} membership`}>
137 <style>{css}</style>
138 <div className="fd-mc-grid">
139 <div className="fd-mc-stage" ref={stage}>
140 <div className="fd-mc-tilt" ref={tilt}>
141 <button type="button" className="fd-mc-card" aria-pressed={flipped} aria-label={flipped ? "Show front of membership card" : "Show back of membership card"} onClick={() => setFlipped((f) => !f)}>
142 <span className="fd-mc-flip" data-flipped={flipped ? "" : undefined}>
143 <span className="fd-mc-face fd-mc-front" aria-hidden={flipped}>
144 <span className="fd-mc-row">
145 <span className="fd-mc-brand">{brand}</span>
146 <span className="fd-mc-kind">Medical membership</span>
147 </span>
148 <svg className="fd-mc-seal" viewBox="0 0 120 120" aria-hidden="true">
149 <circle cx="60" cy="60" r="56" fill="none" stroke="currentColor" strokeWidth="1" />
150 <circle cx="60" cy="60" r="49" fill="none" stroke="currentColor" strokeWidth=".6" strokeDasharray="1.5 3" />
151 <text x="60" y="70" textAnchor="middle" fill="currentColor" style={{ font: `italic 400 38px/1 ${serif}`, letterSpacing: "-1px" }}>MH</text>
152 <text x="60" y="92" textAnchor="middle" fill="currentColor" style={{ font: "500 7px/1 ui-monospace,Menlo,monospace", letterSpacing: "2px" }}>EST. 2019</text>
153 </svg>
154 <span className="fd-mc-chip" aria-hidden="true" />
155 <span className="fd-mc-bottom">
156 <span className="fd-mc-field">
157 <small>Member</small>
158 <b className="fd-mc-name">{member.name}</b>
159 </span>
160 <span className="fd-mc-field fd-mc-r">
161 <small>Since</small>
162 <b>{member.since}</b>
163 </span>
164 </span>
165 <span className="fd-mc-num">
166 {member.number} · {member.clinic}
167 </span>
168 <span className="fd-mc-sheen" aria-hidden="true" />
169 </span>
170 <span className="fd-mc-face fd-mc-back" aria-hidden={!flipped}>
171 <span className="fd-mc-stripe" />
172 <span className="fd-mc-back-body">
173 {backLines.map(([k, v]) => (
174 <span key={k} className="fd-mc-bl">
175 <small>{k}</small>
176 <b>{v}</b>
177 </span>
178 ))}
179 <span className="fd-mc-sig">
180 <svg viewBox="0 0 160 30" aria-hidden="true">
181 <path d="M4 22c10-16 16-16 14-4s8-14 14-10-2 14 6 10 10-12 16-8 0 10 8 8 14-14 22-10 4 10 12 6 16-8 24-4 10 4 20 2" fill="none" stroke="#3A2418" strokeWidth="1.4" strokeLinecap="round" />
182 </svg>
183 </span>
184 <span className="fd-mc-fine">Not valid for emergency treatment. If found, please return to 41 Weymouth Street, London W1G 6NR.</span>
185 </span>
186 </span>
187 </span>
188 </button>
189 </div>
190 <p className="fd-mc-hint">
191 <span aria-hidden="true">↻</span> Tap the card to turn it over
192 </p>
193 </div>
194
195 <div className="fd-mc-copy">
196 <p className="fd-mc-eyebrow">Membership, 2026</p>
197 <h2 className="fd-mc-title">{title}</h2>
198 <p className="fd-mc-lede">{lede}</p>
199 <div className="fd-mc-price">
200 <p className="fd-mc-amt">
201 <span className="fd-mc-cur">{price.currency}</span>
202 {price.monthly}
203 <span className="fd-mc-per">a month</span>
204 </p>
205 <p className="fd-mc-alt">
206 or {price.currency}
207 {price.yearly.toLocaleString("en-GB")} paid yearly, which saves {price.currency}
208 {saving}. No joining fee.
209 </p>
210 </div>
211 <a className="fd-mc-cta" href={cta.href}>
212 {cta.label}
213 </a>
214 </div>
215 <div className="fd-mc-lists">
216 <div>
217 <h3 className="fd-mc-lh">What&apos;s included</h3>
218 <ul className="fd-mc-list">
219 {included.map(([t, d]) => (
220 <li key={t}>
221 <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
222 <circle cx="8" cy="8" r="7.25" stroke="currentColor" strokeWidth="1.2" />
223 <path d="M4.8 8.2l2.1 2 4.3-4.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
224 </svg>
225 <span>
226 <b>{t}</b>
227 {d}
228 </span>
229 </li>
230 ))}
231 </ul>
232 </div>
233 <div className="fd-mc-not">
234 <h3 className="fd-mc-lh">What&apos;s not, honestly</h3>
235 <ul className="fd-mc-list">
236 {excluded.map(([t, d]) => (
237 <li key={t}>
238 <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
239 <circle cx="8" cy="8" r="7.25" stroke="currentColor" strokeWidth="1.2" strokeDasharray="2 2" />
240 <path d="M5.5 10.5l5-5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" />
241 </svg>
242 <span>
243 <b>{t}</b>
244 {d}
245 </span>
246 </li>
247 ))}
248 </ul>
249 </div>
250 </div>
251 </div>
252 </section>
253 );
254}
255
256const css = `
257:where(.fd-mc,.fd-mc *){box-sizing:border-box;margin:0;padding:0;border:0;background:none;font:inherit;letter-spacing:inherit;color:inherit;text-decoration:none;list-style:none}
258:where(.fd-mc,.fd-mc *)::before,:where(.fd-mc,.fd-mc *)::after{box-sizing:border-box}
259:where(.fd-mc svg){display:block;flex-shrink:0}
260:where(.fd-mc button){appearance:none;-webkit-appearance:none;cursor:pointer;text-align:left}
261.fd-mc{
262 --fd-ease-out:cubic-bezier(.22,1,.36,1);--fd-ease-in-out:cubic-bezier(.65,0,.35,1);--fd-spring:cubic-bezier(.34,1.56,.64,1);
263 --fd-dur-1:120ms;--fd-dur-2:240ms;--fd-dur-3:420ms;--fd-dur-4:700ms;
264 --fd-mc-bg:#F1E8DA;--fd-mc-ink:#3A2418;--fd-mc-card:#8C3B22;--fd-mc-foil:#EBCB98;
265 --mut:#7A6556;--line:rgba(58,36,24,.16);
266 --serif:${serif};--sans:ui-sans-serif,-apple-system,BlinkMacSystemFont,"SF Pro Text","Inter","Segoe UI",Roboto,sans-serif;--mono:ui-monospace,"SF Mono","JetBrains Mono",Menlo,monospace;
267 display:block;width:100%;background:var(--fd-mc-bg);color:var(--fd-mc-ink);font:400 15px/22px var(--sans);-webkit-font-smoothing:antialiased;
268 padding:clamp(48px,7vw,104px) clamp(16px,4vw,56px)}
269.fd-mc-grid{max-width:1200px;margin:0 auto;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);grid-template-areas:"stage copy" "stage lists";column-gap:clamp(40px,6vw,96px);align-items:start}
270.fd-mc-stage{grid-area:stage}.fd-mc-copy{grid-area:copy}.fd-mc-lists{grid-area:lists}
271.fd-mc-stage{position:sticky;top:32px;display:flex;flex-direction:column;align-items:center;padding:clamp(24px,4vw,56px) 0;perspective:1100px;touch-action:pan-y}
272.fd-mc-tilt{width:100%;max-width:460px;transform-style:preserve-3d;will-change:transform;--mx:50%;--my:30%}
273.fd-mc-card{display:block;width:100%;aspect-ratio:1.586;border-radius:18px;padding:0;background:none;transform-style:preserve-3d}
274.fd-mc-card:focus-visible{outline:2px solid color-mix(in srgb,var(--fd-mc-card) 70%,transparent);outline-offset:6px}
275.fd-mc-flip{position:relative;display:block;width:100%;height:100%;transform-style:preserve-3d;transition:transform var(--fd-dur-4) var(--fd-ease-in-out)}
276.fd-mc-flip[data-flipped]{transform:rotateY(180deg)}
277.fd-mc-card:active .fd-mc-flip{transition-duration:var(--fd-dur-4)}
278.fd-mc-face{position:absolute;inset:0;display:block;overflow:hidden;border-radius:18px;-webkit-backface-visibility:hidden;backface-visibility:hidden;box-shadow:0 1px 0 rgba(255,255,255,.18) inset,0 30px 50px -24px rgba(58,36,24,.55),0 8px 16px -8px rgba(58,36,24,.35)}
279.fd-mc-front{padding:7% 7.5%;color:var(--fd-mc-foil);background:
280 radial-gradient(120% 90% at 100% 0%,rgba(255,214,170,.22),transparent 55%),
281 repeating-linear-gradient(115deg,rgba(255,255,255,.025) 0 2px,transparent 2px 5px),
282 linear-gradient(160deg,#9C4529 0%,var(--fd-mc-card) 48%,#6A2A17 100%)}
283.fd-mc-row{display:flex;justify-content:space-between;align-items:baseline;gap:12px}
284.fd-mc-brand{font:400 clamp(1rem,2.2vw,1.375rem)/1 var(--serif);letter-spacing:.14em;text-transform:uppercase;font-variant:small-caps}
285.fd-mc-kind{font:500 clamp(.5rem,1.1vw,.625rem)/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;opacity:.8}
286.fd-mc-seal{position:absolute;right:7%;top:28%;width:26%;height:auto;opacity:.55}
287.fd-mc-chip{position:absolute;left:7.5%;top:34%;width:13%;aspect-ratio:1.3;border-radius:5px;background:linear-gradient(135deg,#F3D9A9,#C99A5B 60%,#E9C88E);box-shadow:inset 0 0 0 1px rgba(90,50,20,.35)}
288.fd-mc-chip::before{content:"";position:absolute;inset:30% 0;border-top:1px solid rgba(90,50,20,.35);border-bottom:1px solid rgba(90,50,20,.35)}
289.fd-mc-chip::after{content:"";position:absolute;inset:0 38%;border-left:1px solid rgba(90,50,20,.35);border-right:1px solid rgba(90,50,20,.35)}
290.fd-mc-bottom{position:absolute;left:7.5%;right:7.5%;bottom:19%;display:flex;justify-content:space-between;align-items:flex-end}
291.fd-mc-field{display:flex;flex-direction:column;gap:4px}
292.fd-mc-field small{font:500 clamp(.5rem,1vw,.5625rem)/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;opacity:.7}
293.fd-mc-field b{font:400 clamp(1rem,2.4vw,1.5rem)/1.1 var(--serif);font-style:italic;letter-spacing:.005em;text-shadow:0 1px 0 rgba(0,0,0,.25)}
294.fd-mc-r{text-align:right}
295.fd-mc-r b{font:500 clamp(.75rem,1.6vw,.9375rem)/1.1 var(--mono);font-style:normal}
296.fd-mc-num{position:absolute;left:7.5%;bottom:8%;font:500 clamp(.5625rem,1.2vw,.75rem)/1 var(--mono);letter-spacing:.18em;opacity:.75}
297.fd-mc-sheen{position:absolute;inset:0;background:radial-gradient(55% 65% at var(--mx) var(--my),rgba(255,228,190,.16),transparent 70%);opacity:.5;transition:opacity var(--fd-dur-3)}
298.fd-mc-tilt[data-hover] .fd-mc-sheen{opacity:1}
299.fd-mc-back{transform:rotateY(180deg);background:#EFE3CF;color:var(--fd-mc-ink)}
300.fd-mc-stripe{display:block;height:20%;margin-top:7%;background:#2A1A11}
301.fd-mc-back-body{display:grid;grid-template-columns:1fr 1fr;gap:clamp(8px,2.4vw,14px) 6%;padding:5.5% 7.5%}
302.fd-mc-bl{display:flex;flex-direction:column;gap:3px}
303.fd-mc-bl small{font:500 clamp(.5rem,1vw,.5625rem)/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--mut)}
304.fd-mc-bl b{font:600 clamp(.6875rem,1.5vw,.875rem)/1.25 var(--sans)}
305.fd-mc-sig{display:block;height:clamp(26px,5vw,36px);border-radius:3px;background:repeating-linear-gradient(-45deg,#F8F1E4 0 4px,#EADBC2 4px 6px);padding:3px 8px}
306.fd-mc-sig svg{width:auto;height:100%}
307.fd-mc-bl:nth-child(3){grid-column:1 / -1}
308.fd-mc-fine{align-self:center;font:400 clamp(.5rem,1vw,.625rem)/1.4 var(--sans);color:var(--mut)}
309.fd-mc-hint{margin-top:28px;display:flex;align-items:center;gap:8px;font:400 13px/20px var(--mono);color:var(--mut)}
310.fd-mc-hint span{font-size:16px}
311
312.fd-mc-eyebrow{font:500 12px/16px var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--fd-mc-card)}
313.fd-mc-title{margin-top:18px;font:400 clamp(2rem,3.8vw,3.25rem)/1.06 var(--serif);letter-spacing:-.02em;max-width:18ch}
314.fd-mc-lede{margin-top:20px;max-width:48ch;font-size:1.0625rem;line-height:26px;color:var(--mut)}
315.fd-mc-price{margin-top:36px;padding-top:24px;border-top:1px solid var(--line)}
316.fd-mc-amt{display:flex;align-items:baseline;font:400 clamp(3.5rem,6vw,5rem)/1 var(--serif);letter-spacing:-.04em}
317.fd-mc-cur{font-size:.5em;align-self:flex-start;margin:.2em .06em 0 0}
318.fd-mc-per{margin-left:12px;font:400 15px/22px var(--sans);letter-spacing:0;color:var(--mut)}
319.fd-mc-alt{margin-top:10px;font-size:.875rem;line-height:22px;color:var(--mut)}
320.fd-mc-cta{display:inline-flex;align-items:center;justify-content:center;margin-top:24px;height:52px;padding:0 28px;border-radius:9999px;background:var(--fd-mc-ink);color:var(--fd-mc-bg);font:600 15px/52px var(--sans);transition:background-color var(--fd-dur-1),transform var(--fd-dur-2) var(--fd-spring)}
321.fd-mc-cta:hover{background:var(--fd-mc-card)}
322.fd-mc-cta:active{transform:scale(.96);transition-duration:var(--fd-dur-1)}
323.fd-mc-cta:focus-visible{outline:2px solid color-mix(in srgb,var(--fd-mc-card) 70%,transparent);outline-offset:2px}
324.fd-mc-lists{display:grid;grid-template-columns:1fr 1fr;gap:32px;margin-top:48px}
325.fd-mc-lh{padding-bottom:12px;border-bottom:1px solid var(--line);font:500 12px/16px var(--mono);letter-spacing:.1em;text-transform:uppercase}
326.fd-mc-list{display:grid;gap:16px;margin-top:16px}
327.fd-mc-list li{display:flex;gap:12px;font-size:.875rem;line-height:21px;color:var(--mut)}
328.fd-mc-list svg{margin-top:2px;color:#4F7A52}
329.fd-mc-list b{display:block;font-weight:600;color:var(--fd-mc-ink)}
330.fd-mc-not .fd-mc-list svg{color:var(--fd-mc-card)}
331.fd-mc-not{padding-left:24px;border-left:1px dashed var(--line)}
332@media (max-width:960px){
333 .fd-mc-grid{grid-template-columns:1fr;grid-template-areas:"copy" "stage" "lists"}
334 .fd-mc-stage{position:relative;top:0;padding:48px 8px 0}
335 .fd-mc-lists{margin-top:40px}
336}
337@media (max-width:600px){
338 .fd-mc-lists{grid-template-columns:1fr;gap:36px}
339 .fd-mc-not{padding-left:0;border-left:0}
340}
341@media (prefers-reduced-motion:reduce){.fd-mc *{transition-duration:1ms!important}}
342@media (prefers-contrast:more){.fd-mc{--line:var(--fd-mc-ink)}.fd-mc-sheen{display:none}}
343`;
344
345export function Demo() {
346 return (
347 <div className="fd-mcd">
348 <style>{demoCss}</style>
349 <header className="fd-mcd-nav">
350 <a href="#home" className="fd-mcd-logo">
351 Marlow House
352 <span>Medical</span>
353 </a>
354 <nav aria-label="Main">
355 <a href="#doctors">Our doctors</a>
356 <a href="#membership" aria-current="page">Membership</a>
357 <a href="#clinics">Clinics</a>
358 </nav>
359 <a href="#book" className="fd-mcd-book">020 7946 0321</a>
360 </header>
361 <MembershipCard />
362 </div>
363 );
364}
365
366const demoCss = `
367:where(.fd-mcd,.fd-mcd *){box-sizing:border-box;margin:0;padding:0;font:inherit;color:inherit;text-decoration:none}
368.fd-mcd{min-height:100vh;background:#F1E8DA;color:#3A2418;font:400 14px/20px ui-sans-serif,-apple-system,BlinkMacSystemFont,"SF Pro Text","Inter","Segoe UI",Roboto,sans-serif}
369.fd-mcd-nav{display:flex;align-items:center;justify-content:space-between;gap:20px;height:68px;padding:0 clamp(16px,4vw,56px);border-bottom:1px solid rgba(58,36,24,.14)}
370.fd-mcd-logo{display:flex;align-items:baseline;gap:8px;font:400 20px/24px ${serif};letter-spacing:.1em;text-transform:uppercase}
371.fd-mcd-logo span{font:500 10px/12px ui-monospace,Menlo,monospace;letter-spacing:.16em;color:#8C3B22}
372.fd-mcd-nav nav{display:flex;gap:28px;color:#7A6556}
373.fd-mcd-nav nav a[aria-current]{color:#3A2418;text-decoration:underline;text-underline-offset:6px;text-decoration-color:#8C3B22}
374.fd-mcd-book{font:500 13px/20px ui-monospace,Menlo,monospace}
375@media (max-width:760px){.fd-mcd-nav nav{display:none}.fd-mcd-logo{font-size:17px}}
376`;

More Pricing. Same file contract.

Pricing Tiers Toggle, pricing preview: React pricing section with three plans, a monthly and yearly toggle, odometer prices and a set-apart…

Pricing Tiers Toggle

React pricing section with three plans, a monthly and yearly toggle, odometer prices and a set-apart recommended plan.

Usage Calculator, pricing preview: Usage-based pricing calculator: snapping sliders price every plan at once, flag the cheapest and animate an…

Usage Calculator

Usage-based pricing calculator: snapping sliders price every plan at once, flag the cheapest and animate an itemised bill.

Menu Pricing, pricing preview: Pricing section styled as a printed menu for a coffee subscription: dotted leaders, size columns and a…

Menu Pricing

Pricing section styled as a printed menu for a coffee subscription: dotted leaders, size columns and a pen-circled pick.

Questions about Membership Card

Run npx shadcn@latest add https://freedesignmd.com/r/membership-card.json, or open the page and copy the file into your project. It has zero dependencies besides React. What you copy is the exact file that renders the live demo.

Single plan pricing as a membership card: spring 3D tilt, flips over, with honest included and excluded lists. It is a free, MIT-licensed React pricing component from the freedesignmd library.

Yes. It is free and MIT-licensed, use, modify and ship it in personal and commercial projects without attribution.

All evergreen browsers (3D transforms with backface-visibility). Pointer tilt is skipped with reduced motion.

Yes. It is a plain React component with its own styles, so it runs in Next.js, Vite, Remix and Lovable projects, and it needs no Tailwind setup. It has zero dependencies besides React.