Recovery Check

Shows what would lock a user out if they lost their phone: stale recovery contacts, no backup method, or one phone holding both keys.

StopsLost phone meant lost account

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/recovery-check.json

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

Usage

recovery-check-usage.tsx
import { RecoveryCheck, type IssueId, type RecoveryState } from "@/components/ui/recovery-check"

return <RecoveryCheck state={state} onFix={fix} />

What it catches

  • Recovery email or phone not confirmed within staleAfterDays (default 180)
  • No backup second factor
  • Password-only account
  • The same phone used for SMS codes and recovery
  • Backup codes running low or all used

Props

RecoveryCheck props
PropTypeDefault
state* (required)

Recovery methods on the account and when each was last confirmed.

RecoveryState—
onFix* (required)

Runs the one-tap fix for an issue. Resolve to mark it fixed; reject to show `failedText`.

(issue: IssueId) => void | Promise<void>—
onChangeContact

Optional "Change" next to a stale email or phone, for users who already know it's gone.

(kind: "email" | "phone") => void—
staleAfterDays

Days without confirmation before an email or phone counts as stale.

number180
issueText

Override the title, detail or fix label of any issue. `{email}`, `{phone}`, `{age}` and `{count}` are filled in.

Partial<Record<IssueId, Partial<(typeof COPY)[IssueId]>>>—
title

Templates: `{count}` is the number of open issues.

string"Could you get back in?"
summaryText

Summary line. `{count}` is the number of open issues.

string"{count} things could lock you out of your account."
allClearText

Shown when nothing is at risk.

string"You can get back in even if you lose your phone."
fixedLabel

Shown in place of the fix button once fixed.

string"Fixed"
changeLabel

Label of the optional Change button for a stale contact.

string"Change"
failedText

Shown when onFix rejects.

string"That didn't work. Try again."
locale

Locale for relative ages ("8 months ago").

string—

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

Accessibility

  • Section labelled by its title; open-issue summary in a polite live region
  • A failed fix shows role=alert text
  • After a fix, focus moves to the issue's "Fixed" marker
  • Severity is shown with an icon and text, not colour alone; icons are aria-hidden

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: checkRecovery is pure and can run on the server; the fixes themselves (adding factors, confirming contacts) must be verified server-side.

  • Only as accurate as the RecoveryState you pass in
  • Does not verify that an email or phone still works; it reads the last-confirmed dates
  • Fixes run your onFix callback; nothing changes by itself

What it stops

Lost phone meant lost account

Also known as

account recovery · security checkup · recovery email · recovery phone · 2fa · mobile number · security settings · +91

Field type

Dependencies

Pairs well with