Staaarter

Billing Add On Bundle Pricing

A multi-select add-on list for upsell and checkout flows. Each add-on toggles on and off as a checkbox-style button, and the summary panel recalculates the subtotal, bundle discount, and total on every selection, applying a 10% discount at two items and 20% at three or more.

By Staaarter Team
Billing
Updated May 24, 2026
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/billing-add-on-bundle-pricing.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing14.tsx instead.

Usage

The file also exports billing14Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Billing14, billing14Demo } from "@/components/blocks/billing/billing14";

export default function Page() {
  return <Billing14 {...billing14Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Customize your plan"Heading above the add-on list.
descriptionstring(see source)Supporting sentence under the heading.
addOnsAddOnBundleItem[]noneAdd-ons rendered as selectable rows, in the order given.
defaultSelectedIdsstring[][]Ids selected on first render.
updateLabelstring"Update bundle"Label on the submit button.
classNamestringnoneExtra classes for the outer wrapper.

Types

interface AddOnBundleItem {
  id: string;
  name: string;
  description?: string;
  price: number;
}

Behavior notes

  • Selection is local state; toggling an add-on adds or removes its id from selectedIds and immediately recalculates the summary.
  • The discount rate is a fixed step function: 0% for one item, 10% for two, 20% for three or more. Change discountRateFor in billing14.tsx to match your own pricing rules.
  • Subtotal, discount, and total are derived on every render from the selected add-ons, not stored as separate state, so they can never drift out of sync with the selection.
  • The Update bundle button is disabled while no add-ons are selected, since there'd be nothing to submit.
  • Each add-on row uses role="checkbox" and aria-checked, so selection works with keyboard and screen readers, not just pointer clicks.

Frequently asked questions