shadcn.io is not affiliated with official shadcn/ui
SaaS Upgrade Checkout Block for Vue
A plan upgrade at the moment of payment: Solo to Studio with the prorated amount due today ($5.50 for 11 days), a collapsible that works it out, a card select, and a hold-to-confirm button with a plain Upgrade now for anyone who cannot hold.
Installation
Overview
Charge for the days that are left and not a day more, with this SaaS upgrade checkout for Vue with Ark UI. A compact header from Dapplegrey, a notes app, says what the upgrade charges. In a narrow hairline frame with a plus mark on each corner, the first band names the change (Solo to Studio, $9.00 to $24.00 a month) and lists three things Studio adds, each with a check. The second band holds the one figure that matters, Due today $5.50, prorated for 11 days until the renewal on 29 Oct 2026, and a Collapsible that works it out line by line: the unused part of Solo is credited, the rest of the cycle on Studio is charged, the difference is due, and from the renewal Studio costs its full price. A Native Select picks the card. Confirming is a hold: Hold to upgrade fills over a second and a half, and Enter or Space held does the same; Upgrade now, the only Shine Button, does the same with a press for anyone who cannot or would rather not hold. The result replaces the figure in the same space, says nothing was charged, and Back to Solo undoes it. It's built from Collapsible, Native Select, Long Press Button, Shine Button, Button and Guides, with a CSS entrance only. For plan changes, tier upgrades and any purchase that deserves a deliberate press.
FAQ
How is the amount due worked out?
Each plan's monthly price in cents is multiplied by the days still to run in the cycle (11) and divided by the cycle length (30), rounded to whole cents: $9.00 gives a $3.30 credit and $24.00 gives $8.80, so $5.50 is due today. The constants (FROM, TO, CYCLE_DAYS, DAYS_TO_RUN) sit at the top of the file and the headline figure, the collapsible and the status line all read the same values. In production take this from your billing provider's preview of the change, which also knows about tax and coupons.
How does the hold work, and what if I cannot hold?
Hold to upgrade fills with a sweep of the button's own colour and confirms only if the press lasts the full duration (HOLD_MS, 1.5 seconds); letting go early cancels. Holding Enter or Space on the focused button works too, and it carries a description saying it needs a hold. Under reduced motion the fill fades instead of sweeping. Upgrade now is the same action on a plain press, kept as the primary so nobody is forced to hold.
What happens after I confirm?
The due figure and its working are replaced, in the same space and without the panel changing height, by "You are on Studio", a sentence saying that the upgrade happened in this demo and nothing was charged, the next renewal price, and a Back to Solo button. Focus moves to the heading of the result, both confirm buttons become unavailable and answer if pressed, and Back to Solo returns focus to Upgrade now.
Why a native select for the card?
A choice of one of two saved cards in a form is a native select: it opens the platform's picker on phones, works with every screen reader and needs no menu code. Its label is the visible words "Pay with". The cards here are display strings only, with no numbers beyond the last four digits.
Why are the dates typed?
The renewal date and the days that remain are constants (RENEWS, DAYS_TO_RUN) so the page reads the same wherever and whenever it is opened and the arithmetic can be checked by hand. Nothing is computed from the clock at render.
What stays local, and how do I wire it up?
Everything: no plan is changed and no card is charged. In your app, have both Upgrade now and the hold call one function that asks your server to change the plan with the chosen payment method, show a failure in the status line, and only then show the result.