shadcn.io is not affiliated with official shadcn/ui
Passkey Login Block for Svelte
An online bank's sign-in page and its passkey chooser shown open over a drawn sign-in screen: two passkeys as radio rows, Cancel and Continue, a verifying step and a signed-in result, with the real dialog behind the Use your passkey button.
Installation
Overview
Offer a passkey the way the system does, with this passkey login block for Svelte with Ark UI. A compact header names the page, Sign in to Tarnbridge, an online bank, with three outline Badges and an outline "Use your passkey" button. Below it a framed stage draws the bank's sign-in page, with its top bar, welcome copy and a sign-in card, and over it, shown open in place for the preview, sits the chooser: "Choose a passkey for tarnbridge.example", two passkeys (Maya's iPhone and Work laptop) as radio rows, Cancel and the Shine Button Continue. Continue shows "Verifying with your device, in this demo" for a moment, then "Signed in with…" and a Done button, and the drawn page behind turns into a signed-in one. Pressed, the header's button opens the real Dialog, modal, with a focus trap, Escape and focus returning to the button, from the same content and state. In place on a phone the chooser docks to the foot of the stage. It's built from Dialog, Badge, Button, Shine Button and Guides, with a CSS entrance only. For banks, wallets and any app that asks which passkey to use.
FAQ
Does this call the WebAuthn API?
No. The page never calls navigator.credentials, never reads a credential and never asks your browser for anything: the passkeys are a typed list, "Verifying with your device" is a timer of 800 ms, and the result says nothing was requested or sent. In a product, ask your server for a challenge, call navigator.credentials.get() with it where the code says so, send the signed answer back, and let the browser draw its own chooser; the page here shows what that sheet's choices and result would look like.
Why is the chooser already open, and which part is only for the preview?
A modal open on load would trap focus and hide the page around it, so the docs show the chooser drawn in place, a non-modal dialog on the stage that traps nothing and takes no focus. Its Cancel, Close and Escape (while focus is inside the stage) close it and move focus to the header's button. In your app keep the real Dialog and drop the in-place copy: the in-place state, the scrim with its dialog and the Escape effect. Both wrappers share one content component and the block's state, so a choice made in place is still there in the real dialog.
What does the real dialog do?
It is a modal Dialog: focus moves into it, Tab stays inside, Escape or Cancel close it and focus returns to Use your passkey. Continue runs the same steps as in place, the dialog keeps its height through the three stages, and the polite status message is repeated inside it while it is open, because a modal hides the rest of the page from screen readers.
How should a real chooser handle accounts with no passkey?
Show your password form first and offer the passkey button only when the browser reports support, with PublicKeyCredential.isConditionalMediationAvailable() for autofill. When a visitor has no passkey for your site, the browser's own sheet says so, and your page should say what to do next rather than leave a dead end: a password, or a link to add a passkey after signing in.
Are the three badges true?
They describe passkeys in general. A passkey is bound to your site's domain, so a look-alike page can't use it (phishing resistant); there is nothing for the person to type; and the device checks a fingerprint, face or PIN before it signs (unlocked by your device). They say nothing about Tarnbridge itself, which is fictional.