Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Upgrade Plan Dialog Block for React

A product-analytics usage page with its upgrade dialog shown open: your plan and the next joined by an arrow, a yearly switch, and a table of limits with what you have now and what you would have after.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Show people what they get before they upgrade, with this upgrade dialog for React with Base UI. It opens from the Usage page of Gaugefield, a product-analytics tool: the page's header holds an outline Upgrade Button, and the page itself, a rail, three KPI cells one of which is a project meter nearly full, and a bar chart, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The Dialog is a diff. Your plan, Team, sits muted at the start, an arrow joins it to Scale at the end, raised and marked with a Badge, Recommended. A Switch moves the Scale price between monthly and yearly. Under them a table lists the limits with a Now column and an After column: seats, projects, history and support, each changed limit carrying an arrow and the word more or new. Upgrade to Scale is the only Shine Button; upgrading changes the meter behind the dialog from 18 of 20 to 18 of Unlimited and turns the header's button into Start over. For preview the dialog is drawn open in place when the page loads; the Upgrade button opens the real dialog. For limits, paywalls and any product with plans that differ by numbers.

FAQ

Why is the dialog already open, and what do I keep?

So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Upgrade button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same UpgradeFields component and share the block's state. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.

How do I change the limits?

Edit LIMITS: each has a label, the before text for the plan you are on, the after text for the next one, and a tag, the word shown beside a changed limit (more or new). The table has three columns on every screen, with the tag moving under the value on a phone, and each value is an isolated run of text so it reads right in a right-to-left page. The arrow in an After cell mirrors there. Nothing here is a struck-through price: the dialog shows the new limits, not a discount.

What does the switch change?

Only the Scale head: $119 a month billed monthly, or $99 a month billed yearly, with a line saying what yearly saves. Your own plan's price stays as it is. What an upgrade costs part-way through a billing period (proration) isn't shown here, because that belongs on a billing page: ask your provider for an invoice preview and show it in the same dialog if you need it.

What stays local?

Everything. Upgrading changes the meter and the sentence behind the dialog and says, in the polite status, that nothing was upgraded or charged. The header's button becomes Start over, which puts the page back on Team to try the other cycle. In your app send the plan and the cycle to your server, wait for its answer, and update the meter from what the plan really allows.

Is it accessible from the keyboard?

Yes. The real dialog is named by its title and described by its sentence, focus starts on the yearly switch and stays inside until it closes, and Escape, Not now and the close button return focus to Upgrade. The table has a caption, column headers and row headers, and the switch is named by aria-label. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange.

How does it look on a phone?

The copy shown on load docks to the foot of the page as a bottom sheet with its buttons pinned, and the two plan heads stay side by side with the arrow between them. The table keeps its three columns at 320 pixels, which is why the tags sit under the values. The real dialog keeps the Dialog's own phone layout, a sheet stuck to the bottom of the screen.

  • Pro

    Select Plan Dialog

    Payments and plans

    A static-site host's Sites page with its plan chooser shown open: three plans as rows that unfold to their features, a yearly switch that rewrites the prices and what is due today, and a comparison table behind a disclosure.

  • Pro

    A design tool's account page with its subscription sheet shown open: the plan, billing cycle and seats editable in place, a next-invoice foot worked out from the controls, and a plan card behind it that changes when you save.

  • Pro

    Cancel Subscription Dialog

    Destructive confirms

    A backup service's plan page with its exit flow shown open: an alert dialog in three steps, why you are leaving, an offer matched to the reason, and what ends and when, with a destructive final button and a thin progress bar.

  • Pro

    Upgrade Proration Billing

    Upgrade and downgrade

    Changing plan inside app settings with the bill worked out first: pick a higher plan and the credit for unused days, the new plan's cost for those days, what's due today and the next invoice roll live, then an alert dialog confirms the charge.

  • Pro

    Current Plan Billing

    Plan and usage

    The account's current plan in app settings: plan, price, renewal date and card, a change-plan action, every quota's usage this period on shared hairlines, and the next invoice.

  • Pro

    Usage Meters Billing

    Plan and usage

    Usage meters for an app's settings: one row per quota with its count, a bar that turns to a warning tone at 80% and an over-limit tone past 100%, and a plain line on what happens next.