Pricing Add-on Builder
A free pricing add on builder React component for composing transparent plan totals in Next.js.
Configure your workspace
Add only what moves the work forward
Start with Studio, then choose the capabilities your team needs. Every selection is itemised before checkout.
Customise
Code
<PricingAddOnBuilder basePlan={basePlan} addOns={addOns} selectedIds={selectedIds} onSelectionChange={setSelectedIds} checkoutHref="/checkout" />Pricing Add-on Builder is a free pricing component for Next.js and React, styled with Tailwind and animated with Motion. It presents one to eight optional products as native checkbox rows, keeps selections controlled by the parent, and calculates an itemised recurring total from the base plan and valid selected ids.
The summary stays sticky beside the catalogue on wide screens and returns to normal document flow before the layout becomes narrow. Checked rows state that they are included, every total is formatted through Intl.NumberFormat, and the complete new price is announced in a polite live region. Reduced motion keeps the same checkbox, calculation and checkout workflow while removing row lift, check drawing and digit travel.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/pricing-add-on-builderUsage
"use client";
import { useState } from "react";
import { PricingAddOnBuilder } from "@/components/pricing-add-on-builder";
const basePlan = {
name: "Studio",
price: 39,
period: "month",
};
const addOns = [
{
id: "priority-support",
name: "Priority support",
description: "Replies from a product specialist within four working hours.",
price: 12,
},
{
id: "team-insights",
name: "Team insights",
description: "A clear weekly report from workspace activity.",
price: 18,
},
];
export default function PricingPage() {
const [selectedIds, setSelectedIds] = useState<string[]>([]);
return (
<PricingAddOnBuilder
basePlan={basePlan}
addOns={addOns}
selectedIds={selectedIds}
onSelectionChange={setSelectedIds}
checkoutHref="/checkout"
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| basePlan | { name: string; price: number; period: string } | required | Base recurring plan and price in minor-free display units. |
| addOns | ReadonlyArray<{ id: string; name: string; description: string; price: number }> | required | One to eight optional add-ons with unique ids, descriptions and non-negative prices. |
| selectedIds | ReadonlyArray<string> | [] | Controlled selected add-on ids. Unknown and repeated ids are ignored. |
| currency | string | "GBP" | ISO 4217 currency code passed to Intl.NumberFormat. Invalid values fall back to GBP. |
| locale | string | "en-GB" | Formatting locale passed to Intl.NumberFormat with an en-GB fallback. |
| density | "comfortable" | "compact" | "comfortable" | Controls the vertical spacing inside each add-on row. |
| selectionLift | number | 4 | Selected-row lift in CSS pixels, clamped to the range 0 to 10. |
| totalDuration | number | 0.35 | Total crossfade duration in seconds, clamped to the range 0 to 0.8. |
| summarySide | "left" | "right" | "right" | Wide-screen sticky-summary position. Both options stack on narrow screens. |
| radius | number | 24 | Add-on row and summary radius in CSS pixels, clamped to 0 to 44. |
| onSelectionChange | (ids: string[]) => void | required | Receives the next controlled selection in original catalogue order. |
| checkoutHref | string | required | Meaningful relative or HTTP checkout destination rendered as a real anchor. |
| className | string | undefined | Additional classes merged onto the section. |
Customisation
Pricing Add-on Builder exposes three Tier 3 CSS variables. The accent token colours checked controls and the total, the panel token controls row and summary surfaces, and the divider token separates the itemised total. Density and motion geometry remain available as typed props:
<div
style={{
"--addon-builder-accent": "var(--ring)",
"--addon-builder-panel": "var(--surface)",
"--addon-builder-divider": "var(--border)",
}}
>
<PricingAddOnBuilder
basePlan={basePlan}
addOns={addOns}
selectedIds={selectedIds}
onSelectionChange={setSelectedIds}
checkoutHref="/checkout"
density="compact"
selectionLift={6}
totalDuration={0.25}
summarySide="left"
radius={18}
/>
</div>Frequently asked questions
- Is Pricing Add-on Builder free for commercial use?
- Yes. Pricing Add-on Builder is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Is the add-on builder accessible and performant?
- Yes. It uses a labelled fieldset, native checkboxes, visible focus rings, a semantic itemised summary and a polite total announcement. Motion is limited to transforms, opacity and the check path, while reduced motion updates every state instantly.
- How can I customise the pricing add-on builder?
- Use the density, selectionLift, totalDuration, summarySide and radius props for layout and motion geometry. Override the three component CSS variables to retheme checked controls, panel surfaces and summary dividers without changing selection logic.