Build a pricing surface.
Motion Pricing ships as React + TypeScript source with a small, controlled API, scoped styling, and accessible responsive behavior.
Installation
Use the package manager your app already uses. These commands apply once @motion-pricing/free is available in your configured registry.
npm install @motion-pricing/freePro is delivered as private source. Keep packages/core and packages/pro together in an npm workspace, then build Core before Pro.
Usage
Pricing.tsx
import { useState } from 'react';
import { ProPricing, defaultPlans } from '@motion-pricing/pro';
import '@motion-pricing/pro/styles.css';
export function Pricing() {
const [cycle, setCycle] = useState('monthly');
return (
<ProPricing
plans={defaultPlans}
billingCycle={cycle}
onBillingCycleChange={setCycle}
layout="featured"
animation="lift"
spotlight
showYearlySavings
/>
);
}Plan data
Each plan requires an id, name, description, monthly and yearly prices, and a feature list. Optional fields configure currency, a badge, featured state, CTA text, destination, and accessible label.
types.ts
type PricingPlan = {
id: string;
name: string;
description: string;
monthlyPrice: number;
yearlyPrice: number;
features: Array<string | { label: string; included?: boolean; detail?: string }>;
currency?: string;
currencySymbol?: string;
badge?: string;
featured?: boolean;
ctaLabel?: string;
ctaHref?: string;
ctaAriaLabel?: string;
};Shared types
PricingPlan
Describes one plan shown by both components. Used by PricingTable.plans and ProPricing.plans.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Stable, unique plan identifier. |
name | string | Yes | Plan name displayed in cards and plan tabs. |
description | string | Yes | Short supporting description for the plan. |
monthlyPrice | number | Yes | Price displayed for the monthly billing cycle. |
yearlyPrice | number | Yes | Total price displayed for the yearly billing cycle. |
currency | string | No | ISO currency code; defaults to USD when formatting. |
currencySymbol | string | No | Literal symbol to display instead of locale currency formatting. |
features | Array<string | PricingFeature> | Yes | Included and excluded feature rows. |
badge | string | No | Short status label, such as “Most popular.” |
featured | boolean | No | Marks the plan as featured and selects it initially on mobile. |
ctaLabel | string | No | CTA text; defaults to “Choose {name}.” |
ctaHref | string | No | CTA destination; defaults to #. |
ctaAriaLabel | string | No | Accessible CTA label; defaults to ctaLabel or the generated CTA text. |
PricingFeature
Describes a detailed entry in PricingPlan.features. A plain string is treated as an included feature.
| Field | Type | Default | Description |
|---|---|---|---|
label | string | required | Feature text shown to the visitor. |
included | boolean | true | Marks the feature as included or unavailable. |
detail | string | — | Additional explanatory text displayed below the label. |
BillingCycle
'monthly' | 'yearly'. This controlled value selects the displayed price and billing copy. Used by the Free and Pro billing props and callbacks.
PricingTheme
'light' | 'dark'. Selects the component’s scoped color scheme. Used by PricingTable.theme and ProPricing.theme.
Free props
PricingTable is the primary Free component. Its billing value is controlled by the host.
| Prop | Type | Default | Purpose |
|---|---|---|---|
plans | PricingPlan[] | required | Plan content, prices, features, badge, and CTA metadata. |
billingCycle | BillingCycle | required | Controlled billing value used to calculate every displayed price. |
onBillingCycleChange | (cycle: BillingCycle) => void | — | Shows the built-in billing control and receives the requested cadence. |
theme | PricingTheme | 'light' | Selects the scoped color scheme. |
heading | ReactNode | — | Optional section heading. |
subheading | ReactNode | — | Supporting copy below the heading. |
showBillingToggle | boolean | true | Hides the built-in billing control when false. |
yearlySavingsLabel | string | 'Save 20%' | Display copy beside the yearly option; this value is not calculated. |
priceSuffix | { monthly: string; yearly: string } | { monthly: '/month', yearly: '/year' } | Replaces the cadence copy beside every price. |
className | string | '' | Adds a class to the outer section. |
style | CSSProperties | — | Adds inline styles or scoped CSS custom-property overrides to the outer section. |
styles | PricingTableStyles | — | Adds inline styles to named component parts. |
onPlanSelect | (plan: PricingPlan) => void | — | Runs when a plan CTA is selected; the component does not initiate checkout. |
BillingToggle props
Use BillingToggle when you want the Free billing control outside PricingTable.
| Prop | Type | Default | Purpose |
|---|---|---|---|
value | BillingCycle | required | Controlled selected billing cadence. |
onChange | (cycle: BillingCycle) => void | required | Receives keyboard and pointer selections. |
monthlyLabel | string | 'Monthly' | Monthly option copy. |
yearlyLabel | string | 'Yearly' | Yearly option copy. |
savingsLabel | string | 'Save yearly' | Supplemental copy shown with the yearly option. |
className | string | '' | Adds a class to the radiogroup. |
style | CSSProperties | — | Adds inline styles to the radiogroup. |
buttonStyle | CSSProperties | — | Adds inline styles to both option buttons. |
PricingTableStyles
Inline CSSProperties slots used by PricingTable.styles. featuredCard is applied after card; the top-level style prop is applied after styles.root.
| Slot | Applies to | Description |
|---|---|---|
root | Outer pricing section | Styles the component container before the top-level style prop is merged. |
header | Header wrapper | Styles the heading, supporting copy, and built-in billing control area. |
billingToggle | Built-in BillingToggle | Styles the billing control radiogroup. |
billingToggleButton | Built-in BillingToggle buttons | Styles both monthly and yearly option buttons. |
tabs | Plan tablist | Styles the mobile plan selector. |
grid | Plan grid | Styles the container that arranges the plan cards. |
card | Every plan card | Applies to each plan card. |
featuredCard | Featured plan card | Adds to card styles for a plan with featured set to true. |
cardHeader | Plan card heading | Styles the plan name and description wrapper. |
badge | Plan badge | Styles the optional plan status badge. |
description | Plan description | Styles the individual plan description. |
price | Price row | Styles the formatted price and billing suffix. |
featureList | Feature list | Styles the list that contains a plan’s features. |
feature | Feature row | Styles each included or excluded feature row. |
cta | Plan CTA | Styles the plan’s call-to-action link. |
Pro props
ProPricing includes the controlled pricing behavior of Free, plus layout, animation, and token controls.
| Prop | Type | Default | Purpose |
|---|---|---|---|
plans | PricingPlan[] | required | Plan content, prices, features, badge, and CTA metadata. |
billingCycle | BillingCycle | required | Controlled billing value used to calculate every displayed price. |
onBillingCycleChange | (cycle: BillingCycle) => void | — | Renders and controls the built-in billing selector when supplied. |
theme | PricingTheme | 'light' | Selects the component color scheme. |
layout | PricingLayout | 'standard' | Changes information density and plan presentation. |
animation | AnimationPreset | 'subtle' | Controls card entrance and hover motion. |
spotlight | boolean | false | Adds a pointer-following surface glow and border reflection. |
tokens | ProPricingTokens | — | Typed overrides for accent, surfaces, text, border, radius, gap, and font. |
heading | ReactNode | — | Optional component heading. |
eyebrow | ReactNode | — | Optional content displayed above the heading. |
subheading | ReactNode | — | Supporting copy below the heading. |
showBillingToggle | boolean | true | Allows the built-in billing selector to be hidden. |
showYearlySavings | boolean | false | Shows calculated annual savings and the yearly Best value label. |
className | string | '' | Adds a class to the outer section. |
style | CSSProperties | — | Adds inline styles to the outer section after styles.root. |
styles | ProPricingStyles | — | Adds inline styles to named component parts. |
onPlanSelect | (plan: PricingPlan) => void | — | Notifies the host when a plan CTA is selected; it performs no checkout itself. |
PricingLayout
'standard' | 'compact' | 'featured' | 'comparison'. Used by ProPricing.layout. standard is the default card grid, compact reduces visual density, featured emphasizes a featured plan, and comparison renders a feature comparison table.
AnimationPreset
'none' | 'subtle' | 'lift' | 'cascade'. Used by ProPricing.animation to select the card motion treatment.
Customization tokens
ProPricingTokens
Optional string values passed through ProPricing.tokens as scoped CSS custom properties.
| Field | Description |
|---|---|
accent | Primary interactive and emphasis color. |
accentContrast | Text or icon color placed over the accent color. |
background | Outer component background. |
surface | Card and elevated surface color. |
text | Primary text color. |
muted | Secondary text and subdued UI color. |
border | Border and separator color. |
radius | Card and control corner radius. |
cardGap | Spacing between pricing cards. |
fontFamily | Font family for the component. |
ProPricingStyles
Inline CSSProperties slots used by ProPricing.styles. featuredCard is applied after card; the top-level style prop is applied after styles.root. Free can also be customized through its scoped --mp-* CSS variables.
| Slot | Applies to | Description |
|---|---|---|
root | Outer pricing section | Styles the component container before the top-level style prop is merged. |
header | Header wrapper | Styles the eyebrow, heading, supporting copy, and billing control area. |
billingToggle | Built-in billing control | Styles the Pro monthly/yearly selector. |
tabs | Plan tablist | Styles the plan selector above the card grid. |
grid | Plan grid | Styles the container that arranges the plan cards. |
card | Every plan card | Applies to each plan card. |
featuredCard | Featured plan card | Adds to card styles for a plan with featured set to true. |
cardHeader | Plan card heading | Styles the plan index, name, and badge wrapper. |
badge | Plan badge | Styles the optional plan status badge. |
description | Plan description | Styles the individual plan description. |
price | Price row | Styles the formatted price, billing suffix, and yearly-savings content. |
featureList | Feature list | Styles the list that contains a plan’s features. |
feature | Feature row | Styles each included or excluded feature row. |
cta | Plan CTA | Styles the plan’s call-to-action link. |
comparisonTable | Comparison table wrapper | Styles the focusable, horizontally scrollable comparison table region. |
Responsive and accessible behavior
Desktop layouts display plans side by side. At mobile component widths, plans become keyboard-operable tabs so visitors can focus on one decision at a time. Billing controls use radio semantics and arrow keys, data tables reflow into readable rows, and all motion respects prefers-reduced-motion.