Downgrade impact
ProWhat moving to a smaller plan takes away, before you confirm: the features you lose (and what happens to anything that used them), the new monthly total, and when it takes effect. Confirm stays locked until you acknowledge the losses.
Preview
Install
With the Candor CLI
First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/downgrade-impact
Brings in: button, locale, locked, ops, utils · npm: lucide-react@^1.67.0
Usage
"use client"
import { DowngradeImpact } from "@/components/downgrade-impact"
import type { PlanTier } from "@/lib/ops"
const enterprise: PlanTier = { id: "enterprise", name: "Enterprise", perSeat: 499, tagline: "Everything in Team, plus people behind it", includes: ["Everything in Team", "Security and deployment controls", "A named engineer on your account"] }
const team: PlanTier = { id: "team", name: "Team", perSeat: 249, tagline: "The whole product for an in-house team", includes: ["Chat, agents and reports", "Approvals and audit log", "SSO sign-in"] }
export default function Example() {
return (
<DowngradeImpact
className="max-w-xl"
from={enterprise}
to={team}
seats={8}
losses={[
{ feature: "Deployment controls", consequence: "Your two Production deploy windows are removed; deploys follow the default approval rules." },
{ feature: "A named engineer", consequence: "Support moves to the shared queue." },
]}
effectiveAt="2026-12-01"
onConfirm={() => {}}
onCancel={() => {}}
/>
)
}<DowngradeImpact>
| Prop | Type | Default | Description |
|---|---|---|---|
| fromrequired | PlanTier | — | The current plan. |
| torequired | PlanTier | — | The smaller plan being moved to. |
| seatsrequired | number | — | Seats on the account, for the old and new monthly totals. |
| lossesrequired | { feature: string; consequence: string }[] | — | What goes, and what happens to things that depended on it. |
| effectiveAtrequired | string | — | When the new plan takes effect, as an ISO date. |
| onConfirmrequired | () => void | — | Called on confirm, which stays locked until the losses are acknowledged. |
| onCancel | (() => void) | undefined | — | Shows a button to keep the current plan; called when it's clicked. |
| className | string | undefined | — | Extra classes for the outer element. |
Strings
The fixed words, in English by default. Change any of them under downgradeImpact in <LocaleProvider strings={{ … }}>; the table is exported as downgradeImpactStrings.
| Key | English |
|---|---|
| moveTo | Move to {plan} |
| to | to |
| price | ${amount} |
| perMonth | a month |
| youllLose | You’ll lose |
| takesEffect | Takes effect on {date}. Until then nothing changes. |
| understand | I understand what {plan} doesn’t include. |
| keep | Keep {plan} |
| tickFirst | Tick the box first. |