KQ-1710 · RECOVERY/ROUTE
Recovery Route
An account recovery chooser drawn as a map: you on one side, the ways back in on the other — backup code, recovery email, trusted contact, support review — each with how long it takes. Choosing one draws the route from you to its card, revealed along its own length by a mask whose stroke runs on springs.glide with a traveller riding the leading point, and the card's notch answers with a ring on springs.snap; the steps slide in 16px from the side the choice came from under an honest wait counted from now. The methods are a real radio group — arrows choose and skip the ones not set up — and below 44rem of container the route runs down a gutter beside the list.
Locked out of mara@fieldline.io?
Choose the way back in. Each one says how long it takes.
route · Recovery email · ~5 min
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/recovery-route
Props
- methods
- RecoveryMethod[]
- default defaultRecoveryMethods
- The ways back in: { id, kind, label, detail?, wait, waitMinutes?, target?, steps?, available?, reason? }.
- account
- { name, email }
- default defaultRecoveryAccount
- The locked account, named in the heading and on your node.
- now
- number
- default defaultRecoveryNow
- The clock (epoch ms) every "expected by" is counted from.
- value / defaultValue
- string | null
- default — / null
- The chosen method, controlled or initial.
- onValueChange
- (id) => void
- default —
- Fires with the id from the press or arrow that chose a method.
- onChoose
- (method) => void
- default —
- Fires with the whole method from the press or arrow that chose it.
- onSubmit
- (method, { stage, code?, message? }) => void | Promise<void>
- default —
- A step was submitted. A promise holds its button; resolving advances the step, a rejection keeps it and what was typed, with the message.
- onContactSupport
- () => void
- default —
- "Contact support" was pressed under everything.
- status
- "ready" | "loading" | "error"
- default "ready"
- Skeleton cards while loading; a message and Try again on error.
- onRetry
- () => void
- default —
- Try again was pressed after loading failed.
- routeStyle
- "curve" | "dotted" | "metro"
- default "curve"
- A smooth curve, round dots, or an orthogonal metro line with a rail down its middle.
- density
- "compact" | "cozy" | "roomy"
- default "cozy"
- Card padding, gaps and type size.
- tone
- "calm" | "warm" | "plain"
- default "calm"
- The route, your node's ring, the chosen card's edge and the buttons: cobalt, amber or ink.
- formatTime
- (at, now) => string
- default recoveryTime (UTC)
- Writes an expected time; the default reads "today 09:35" or "Thu 09:30" in UTC so server and browser agree.
- title
- string
- default "Locked out of {email}?"
- The heading.
- maxHeight
- number
- default 560
- Tallest the panel grows, in px, before its body scrolls.
- disabled
- boolean
- default false
- Nothing can be chosen or submitted.
- className
- string
- default —
- Classes for the wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
| methods | RecoveryMethod[] | defaultRecoveryMethods | The ways back in: { id, kind, label, detail?, wait, waitMinutes?, target?, steps?, available?, reason? }. |
| account | { name, email } | defaultRecoveryAccount | The locked account, named in the heading and on your node. |
| now | number | defaultRecoveryNow | The clock (epoch ms) every "expected by" is counted from. |
| value / defaultValue | string | null | — / null | The chosen method, controlled or initial. |
| onValueChange | (id) => void | — | Fires with the id from the press or arrow that chose a method. |
| onChoose | (method) => void | — | Fires with the whole method from the press or arrow that chose it. |
| onSubmit | (method, { stage, code?, message? }) => void | Promise<void> | — | A step was submitted. A promise holds its button; resolving advances the step, a rejection keeps it and what was typed, with the message. |
| onContactSupport | () => void | — | "Contact support" was pressed under everything. |
| status | "ready" | "loading" | "error" | "ready" | Skeleton cards while loading; a message and Try again on error. |
| onRetry | () => void | — | Try again was pressed after loading failed. |
| routeStyle | "curve" | "dotted" | "metro" | "curve" | A smooth curve, round dots, or an orthogonal metro line with a rail down its middle. |
| density | "compact" | "cozy" | "roomy" | "cozy" | Card padding, gaps and type size. |
| tone | "calm" | "warm" | "plain" | "calm" | The route, your node's ring, the chosen card's edge and the buttons: cobalt, amber or ink. |
| formatTime | (at, now) => string | recoveryTime (UTC) | Writes an expected time; the default reads "today 09:35" or "Thu 09:30" in UTC so server and browser agree. |
| title | string | "Locked out of {email}?" | The heading. |
| maxHeight | number | 560 | Tallest the panel grows, in px, before its body scrolls. |
| disabled | boolean | false | Nothing can be chosen or submitted. |
| className | string | — | Classes for the wrapper. |