Skip to content

Components / Sections

Usage Pricing

Usage-based pricing: a slider of monthly usage and every plan priced at the usage picked, each price rolling to its new figure, the cheapest plan for that usage lit and badged. A plan is a base price, what it includes, the rate for each block over it and an optional limit, past which it says so instead of a price. The slider is a group of radios drawn as a track with a thumb, so arrow keys and focus are native; every price at every stop is worked out at build and :has() shows the one picked, and a screen reader hears that price, not the reel. Zero JavaScript.

Live demo

Pricing

Pay for what you send

Sample plans and prices, made up for this demo.

Usage a month
  • Lowest price at this usage

    Free

    For a side project

    $0 / monthPast this plan's limitPast this plan's limitPast this plan's limitPast this plan's limit

    $0 includes 3,000 emails

    • One domain
    • Logs for a day
    Start free
  • Lowest price at this usage

    Pro

    For a product

    $20 / month$20 / month$65 / month$200 / month$875 / month

    $20 includes 50,000 emails, then $0.90 / 1,000 emails

    • Ten domains
    • Webhooks
    • Logs for 30 days
    Start with Pro
  • Lowest price at this usage

    Scale

    For volume

    $90 / month$90 / month$90 / month$90 / month$540 / month

    $90 includes 250,000 emails, then $0.60 / 1,000 emails

    • Dedicated IP
    • Logs for a year
    Talk to us

Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.

Variants · each row writes the attribute the prop writes; the section's own CSS answers

tone
density

Measured

JavaScript of its own

0 B

CSS 13.9 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.

Browser support

Baseline · widely available

Chrome 105 · Firefox 121 · Safari 15.4; needs has. Elsewhere: without :has() the first stop's prices stay.

Install Pro

The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:

terminal
npx shadcn@latest add @moonarc-pro/pricing-usage
src/pages/index.astro
---
import PricingUsage from '@/components/moonarc/pro/PricingUsage.astro';
---
<PricingUsage
  eyebrow="Pricing"
  unit={{ one: 'email', many: 'emails' }}
  stops={[3000, 50000, 100000, 500000, 1000000]}
  start={1}
  plans={[
    { name: 'Free', base: 0, included: 3000, max: 3000, features: ['One domain'], action: { href: '/signup/', label: 'Start free' } },
    { name: 'Pro', base: 20, included: 50000, over: 0.9, per: 1000, features: ['Ten domains', 'Webhooks'], action: { href: '/signup/', label: 'Start with Pro' }, featured: true },
    { name: 'Scale', base: 90, included: 250000, over: 0.6, per: 1000, features: ['Dedicated IP'], action: { href: '/contact/', label: 'Talk to us' } },
  ]}
>
  <span slot="headline">Pay for what you <em>send</em></span>
</PricingUsage>

Without a key the registry answers 401 with an upgrade message.

Props

PropTypeDefaultDescription
plans{ name; blurb?; base; included; over?; per?; max?; features?; action; featured? }[]noneOne to four plans. The price at a usage is base plus, for every block of per units (1,000 when unset) over included, over. A plan without over, or past its max, prints the overLimit words instead of a price.
stopsnumber[]noneTwo to eight usage values, low to high: the slider's stops.
startnumber0The stop picked at first, by index.
unit{ one: string; many: string }noneThe unit, singular and plural.
currencystring'$'The currency symbol, printed before the figure.
localestring'en-US'A BCP 47 locale for the numbers (the stops are compact: 50K, 1M).
wordsPartial<{ usage; perPeriod; includes; then; overLimit; best }>noneEvery word the section prints around the figures.
eyebrowstringnoneA short line above the heading.
headlinestringnoneThe heading. Slot "headline" wins and may hold an <em>.
copystringnoneA line under the heading.
level2 | 32Heading level of the heading.
tone'surface' | 'muted' | 'ink' | 'brand'unset (paints nothing)The section's ground.
density'compact' | 'cozy' | 'roomy''cozy'Block padding ×0.8 / ×1 / ×1.25 through --ma-density.

Theming and overrides

The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.

Classes

.ma-pusage.ma-pusage__action.ma-pusage__badge.ma-pusage__blurb.ma-pusage__copy.ma-pusage__eyebrow.ma-pusage__features.ma-pusage__figure.ma-pusage__head.ma-pusage__headline.ma-pusage__inner.ma-pusage__input.ma-pusage__legend.ma-pusage__name.ma-pusage__period.ma-pusage__plan.ma-pusage__plans.ma-pusage__price.ma-pusage__readout.ma-pusage__reel.ma-pusage__slider.ma-pusage__sr.ma-pusage__stop.ma-pusage__terms.ma-pusage__thumb.ma-pusage__track.ma-pusage__window

Slots

slot="headline"

Reduced motion

The prices change in place without rolling and the thumb moves at once.

With ClientRouter

CSS only; the stop picked resets on a fresh page.

Why it is built this way

Replaces: Pricing calculators with a usage slider · Usage sliders on API pricing pages. See the migration table.

1,284

A number whose digits roll to the new value when it changes.

newly · Chrome 125 · Firefox 118 · Safari 15.4click

sample prices

Starter

$12/mo$115/yr

one site

Studio

$48/mo$460/yr

up to ten

A monthly / yearly toggle whose prices roll to the other amount instead of swapping.

newly · Chrome 125 · Firefox 129 · Safari 17.5click

Free

$0/yr

MIT, forever

  • 125 primitives, no account, no token
  • Runtime, GSAP and Lenis adapters
  • Public shadcn registry
  • MCP server
Set up in five minutes

Pro

$129/yr

One person, billed yearly

  • 108 sections and 11 GPU effects, demos never gated
  • Every template: Waitlist, Launch, Agentic, Studio, Agency, Atelier, Gather, Creator, Endpoint, Homescreen, Estate, Practice, and Stay
  • audit_motion and measure_budget, locally and in CI
  • compose_section with a total cost
  • New components monthly, dated changelog
  • Email support within 2 working days
Not open yet: see the plan

Team

$349/yr

Up to 10 people, one invoice

  • Everything in Pro, for the whole team
  • One key for the team, locally and in CI
  • Move up from Pro at any time
  • More than 10 people: email us
Talk to us

Shows pricing plans side by side, with an annual/monthly toggle that rolls every price digit by digit to the other period with zero JavaScript (radios, :has and NumberFlow), the highlighted plan wearing a travelling border beam, cards revealed with a stagger.

newly · Chrome 125 · Firefox 128 · Safari 16.4scrollclick

A feature-by-plan comparison: the highlighted plan's column lit, rows revealed with a 40 ms stagger as the table scrolls into view, and a header row that sticks when you cap the table's height.

every browserscroll

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown