Password-to-Passkey Fallback UI Patterns

Passkeys rarely launch into a greenfield: most products carry an existing password base, and the transition period — where some users have passkeys, some have both, and some have neither — is where UX goes wrong. Strand a user with a lost device and no password, or nag them with an upgrade prompt on every visit, and adoption suffers. This page catalogues the coexistence patterns: the upgrade prompt, the dual-path form, cross-device fallback, and the rule that the recovery path stays until a backup exists. It sits under Progressive Enhancement and Passkey Fallback Flows.


Pattern Reference

Pattern When to use Anti-pattern it prevents
Dual-path sign-in form Always, during transition Forcing a single method
Post-login upgrade prompt User has password, no passkey, supported device Blocking the app behind enrolment
Cross-device (hybrid) fallback Local ceremony fails or no platform authenticator Dead-ending on a kiosk
Backup-before-removal rule Before hiding the password path Account lockout on device loss
Frequency-capped nudge Re-prompting non-adopters Prompt fatigue

The state diagram below shows the user’s journey from password-only to passkey-primary, with the password path retained until a backup passkey (or recovery method) exists.

Password-to-passkey adoption states States: password-only, offered upgrade, one passkey plus password, passkey-primary with backup. Transitions gated on enrolment and backup existence. Password only supported Upgrade prompt (post-login, capped) enrol 1 passkey + password password retained backup Passkey-primary + recovery Never remove password until a backup passkey or recovery exists

Root Cause Analysis (of poor coexistence UX)

1. Removing the password immediately after first enrolment. A single device-bound passkey plus no password equals a lockout the moment the device is lost — connect this to building a passkey account recovery flow.

2. Prompting to upgrade before sign-in. Blocking the app behind enrolment tanks conversion; the prompt belongs after a successful login.

3. No path on a device without a platform authenticator. A kiosk or shared desktop with no biometric dead-ends unless hybrid transport is offered.

4. Unbounded re-prompting. Nagging on every visit trains users to dismiss reflexively.


Step-by-Step Resolution

Step 1 — Dual-path form

Render both methods; let feature detection reveal the passkey affordance (see feature-detecting passkey support).

<form method="post" action="/login">
  <input name="username" autocomplete="username webauthn" required />
  <button type="button" id="passkey-btn" hidden>Sign in with a passkey</button>
  <details>
    <summary>Use your password instead</summary>
    <input name="password" type="password" autocomplete="current-password" />
    <button type="submit">Sign in</button>
  </details>
</form>

Step 2 — Post-login, frequency-capped upgrade prompt

async function maybePromptUpgrade(user: { hasPasskey: boolean }) {
  const caps = await getCapabilities();
  const lastAsked = Number(localStorage.getItem('pk_prompt_at') ?? 0);
  const cooldownMs = 14 * 24 * 60 * 60 * 1000; // ask at most every 14 days
  if (user.hasPasskey || !caps.api || Date.now() - lastAsked < cooldownMs) return;
  localStorage.setItem('pk_prompt_at', String(Date.now()));
  showUpgradeSheet(); // "Sign in faster next time — add a passkey"
}

Step 3 — Cross-device fallback on ceremony failure

On NotAllowedError/ConstraintError, present “Use a passkey on another device” (hybrid) alongside the password, rather than an error.

function showFallback({ reason }: { reason: string }) {
  document.getElementById('password-path')!.hidden = false;
  document.getElementById('use-another-device')!.hidden = false; // triggers a modal get() → QR/hybrid
}

Step 4 — Enforce backup-before-removal

Only hide the password path once the account has two authenticators or a verified recovery method. This is a server-side policy the client reads.


Verification and Testing

Drive the flow in an emulator: register one passkey, confirm the password path is still present; register a second, confirm the “remove password” option unlocks. Assert the upgrade prompt respects the cooldown by advancing the clock in a test. Verify that with JavaScript disabled the <details> password path is fully usable (no passkey affordance required). Simulate NotAllowedError via the DevTools virtual authenticator (cancel the prompt) and confirm the fallback appears rather than an error page.


Pitfalls

1. Lockout by early password removal. Keep the recovery path until a backup exists.

2. Prompt fatigue. Cap the nudge frequency and never gate the app behind it.

3. No kiosk path. Always offer hybrid/cross-device as a fallback.


Related