Account Deletion Readback

Reads back everything an account deletion loses or keeps charging for, so users do not delete more than they expect or keep paying an app store.

StopsDeleted account still billing subscriptions

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/account-deletion-readback.json

The files land in your project. They're yours to edit.

What it catches

  • Teams or workspaces where the user is the only owner, with a transfer action
  • App Store and Google Play subscriptions that keep billing after the account is gone
  • Deleting mid-way through a paid period, with an option to delete when it ends
  • No data export taken yet (the button reads "Delete without export")
  • A typed confirmation that does not match the phrase

Props

AccountDeletionReadback props
PropTypeDefault
email* (required)

The account being deleted.

string—
items

What is deleted: data, files, projects.

DeletionItem[][]
teams

Teams or workspaces the user belongs to; sole-owner ones get a transfer prompt.

DeletionTeam[][]
subscriptions

Paid plans tied to the account, including app store plans.

DeletionSubscription[][]
retained

What the law makes you keep, e.g. "Invoices, for 8 years (tax law)".

string[][]
graceDays

Days the account can still be restored. 0 means immediate.

number30
now

"Now" in epoch ms, for deterministic rendering. Read from the clock after mount when omitted.

number—
locale

BCP 47 locale used for dates. Defaults to the browser locale.

string—
confirmPhrase

What must be typed to confirm. Defaults to the email, matched without case.

string—
orphanTeams

Sole-owner teams block deletion until transferred ("block"), or are deleted with the account ("delete").

"block" | "delete""block"
scheduleOption

Offer "delete when the paid period ends" when a subscription has a future `endsOn`. Immediate deletion stays the default.

booleantrue
onExport

Starts the export. May return a Promise; the button shows progress.

() => void | Promise<void>—
onTransfer

Opens or performs a transfer. Update `teams` when it is done. May return a Promise.

(teamId: string) => void | Promise<void>—
onDelete

Deletes the account now, or schedules it (`timing.when === "periodEnd"`). May return a Promise; double submits are ignored.

(timing: DeletionTiming) => void | Promise<void>—
messages

Any visible string.

Partial<Omit<AccountDeletionMessages, "storeName">> & { storeName?: Partial<AccountDeletionMessages["storeName"]> }—

* required. Also accepts the native props of <section> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Labelled confirmation input with aria-invalid and aria-describedby on a mismatch
  • Timing options are native radio inputs with labels
  • Export progress is announced in an aria-live="polite" region
  • The Delete button is described by the list of what still blocks it; focus moves to the first fix button

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Authorise the deletion on the server, re-check ownership and active subscriptions there, and run any scheduled deletion and retention from the backend.

  • Only shows the items, teams and subscriptions you pass in; it does not discover them
  • Whether a store plan is cancelled comes from your data (e.g. the store's server API), not from the component
  • It does not perform deletion, export or transfer; those are your callbacks

What it stops

Deleted account still billing subscriptions

Also known as

delete account · close account · account settings · gdpr · dpdp · data export · app store subscription · play store billing

Field type

Dependencies

Pairs well with