KQ-1703 · PAUSE/INSTEAD

Pause Instead

A cancellation flow built from plan, usage and offers: the reason, what changes, then a plain choice, in a step bar whose pill slides on springs.snap while each step cross-slides 8px on springs.glide inside a box that glides to its measured height. When "What changes" comes into view the losses switch off one at a time inside the 600ms budget — a mini switch flips on snap, a strike sweeps on glide, or a tile's live bar drains — and the pause offer slides up 16px beneath on glide with a resume date that rolls as the length changes. Reasons and pause lengths are radiogroups (arrows, Home, End), every step and decision is a real button, and a step change moves focus to its heading.

KQ-1703 · PAUSE/INSTEAD

Fieldline · Billing

Cancel Team

8 seats · $12 a seat a month · paid through 12 Nov 2026 (23 days left)

  1. Reason
  2. What changes
  3. Decide

Why are you cancelling?

One answer helps us improve. It doesn't change your options.

step 1 of 3 · reason · 3 things switch off

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/pause-instead

Props

plan
PauseInsteadPlan
default defaultPauseInsteadPlan
The plan being cancelled: { id, product, name, price, seats, cycle, renewsAt, currency? }.
usage
PauseInsteadLoss[]
default defaultPauseInsteadUsage
What switches off when the plan ends, in order: { id, label, detail, figure?, icon? }.
keeps
PauseInsteadKeep[]
default defaultPauseInsteadKeeps
What stays whatever is chosen: { id, label }.
reasons
PauseInsteadReason[]
default defaultPauseInsteadReasons
The reasons offered on the first step: { id, label }.
offers
PauseInsteadOffers
default defaultPauseInsteadOffers
{ pause?: { months, defaultMonths? }, downgrade?: { plan, price, keeps } }; omit one to leave it out.
now
number
default plan.renewsAt − 23 days
The moment "days left" counts from, in ms.
step / defaultStep
"reason" | "losses" | "decide" | "done"
default — / "reason"
The step shown, controlled or initial.
onStepChange
(step) => void
default —
Fires from the button that moved the flow.
onCancel
(details: { reason, note }) => void | Promise
default —
Cancel was confirmed; a promise holds the button and a rejection shows its message.
onPause
(details: { months, resumesAt, reason, note }) => void | Promise
default —
A pause was chosen, with its length and the date billing resumes.
onDowngrade
(details: { plan, reason, note }) => void | Promise
default —
The cheaper plan was chosen.
onExit
(outcome: "kept" | "paused" | "downgraded" | "cancelled") => void
default —
The flow was left: Keep my plan, or Done after an outcome.
status
"ready" | "loading" | "error"
default "ready"
Whether the plan's data has arrived.
onRetry
() => void
default —
Try again was pressed after the plan failed to load.
listStyle
"switch" | "strike" | "tiles"
default "switch"
How the losses are drawn: rows with a switch that flips off, rows struck through, or figure tiles that drain.
density
"compact" | "cozy" | "roomy"
default "cozy"
Padding, gaps and type size.
tone
"calm" | "warm" | "mono"
default "calm"
The offer's wash, the primary fill and the step pill: cobalt, amber pigment or ink.
dimInterval
number
default 150
Milliseconds between one loss switching off and the next; the run never passes 600ms.
formatDate
(ms) => string
default "12 Nov 2026" (UTC)
How a date is written.
formatMoney
(amount, currency) => string
default Intl currency
How a price is written.
maxHeight
number
default 560
The surface's height cap in px; the steps scroll inside it with edge fades.
disabled
boolean
default false
Every action is unavailable; the steps can still be read.
className
string
default —
Classes for the surface.