Skip to content
weftGitHub

PlanPicker

Compare plans, see the price difference, and switch.

SourcePackage @weft-js/warp

Preview

tsx
import { state } from '@weft-js/core'import { PlanPicker, Toaster } from '@weft-js/warp'import type { BillingPlan } from '@weft-js/warp'export function Team() {  const current = state('team')  const change = async (plan: { id: string }) => {    await wait(700)    current.value = plan.id  }  return (    <>      <PlanPicker plans={PLANS} current={current.value} seats={8} daysLeft={9} losses={plan => (plan.id === 'hobby' ? ['Preview environments', '7 of your 10 seats'] : [])} onChange={change} />      <Toaster />    </>  )}const PLANS: BillingPlan[] = [  { id: 'hobby', name: 'Hobby', price: 0, description: 'For side projects.', features: ['3 seats', '100 deploys a month', '1 region'] },  { id: 'team', name: 'Team', price: 24, description: 'For product teams.', features: ['10 seats', 'Unlimited deploys', '5 regions', 'Preview environments'] },  { id: 'scale', name: 'Scale', price: 64, description: 'For many teams.', features: ['50 seats', 'Unlimited deploys', 'Every region', 'SSO and audit export'] },]const wait = (ms: number) => new Promise<void>(done => { setTimeout(done, ms) })

Installation

npm install @weft-js/warp

Usage

tsx
import { PlanPicker } from '@weft-js/warp'

Accessibility

  • This has no shortcuts of its own: controls inside it use Tab, Enter and Space as usual, and warp's parts keep their roles and labels.

API Reference

PropTypeDefaultDescription
plansBillingPlan[]—The plans to compare, one card each.
currentstring—The id of the plan the workspace is on.
selectedState<string>—The checked card, when something else needs to set it.
intervalState<BillingInterval>—Monthly or yearly, when you want to own it.
seatsnumber—Seats, for the price.
daysLeftnumber—Days left in this period, for the proration.
periodDaysnumber30The length of a period in days.
currencystring—The ISO 4217 code prices are shown in, such as EUR.
localestring—The language and region used to format values.
preview((plan: BillingPlan, interval: BillingInterval) => Proration | Promise<P…—Your server's proration, to replace the built-in one.
losses((plan: BillingPlan) => string[])—What stops working on a downgrade.
EventTypeDefaultDescription
onChange(plan: BillingPlan, interval: BillingInterval) => string | void | Promis…—Makes the change. Resolve with a message to keep the dialog open and show it.

Parts

Every element carries a stable name, so you can style it from your own CSS: [data-scope="stack"] [data-part="grid"]

gridnameradiopricetotal

RelatedUsage meterInvoicesPayment methods