KQ-1706 · PASSKEY/ENROL

Passkey Enrol

A passkey setup step: a key inside a disc with rings round it, a short explanation, Create, and the devices already enrolled. While the platform prompt is open the rings draw slowly one after another on a symmetric tween and then turn very slowly, only in view and in a visible tab; success contracts every ring onto the key on springs.glide, outer ones a beat behind, into a solid mark that settles on springs.snap with a check drawn on springs.flick, while the new device slides into the list from 8px on glide with a New chip landing on springs.recoil. Rename edits in place (Enter saves, Escape cancels), Remove asks in the row, and cancelled prompts and unsupported browsers each get a plain message and a fallback.

KQ-1706 · PASSKEY/ENROL

Add a passkey

Sign in with your fingerprint, face or screen lock. Nothing to remember, nothing to phish.

Your passkeys

ana@waylight.studio
  • Work laptopAdded 3 Sep · used today
  • Hardware keyAdded 21 Jul · used 9 days ago

2 passkeys on Ana's account. Your password can retire.

2 passkeys · password can retire

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/passkey-enrol

Props

account
PasskeyAccount
default defaultPasskeyAccount
Whose passkeys these are: { name, email }.
devices / defaultDevices
PasskeyDevice[]
default — / defaultPasskeyDevices
The enrolled devices: { id, name, kind, addedAt, lastUsedAt? }, controlled or initial.
onDevicesChange
(devices) => void
default —
Fires with the whole list after an enrol, a rename or a remove.
onEnrol
() => PasskeyDevice | Promise<PasskeyDevice>
default —
Opens the platform prompt; resolve with the new device, reject with { reason: "cancelled" | "unsupported" | "error" } or the platform's NotAllowedError.
onRename
(device, name) => void
default —
A device was renamed.
onRemove
(device) => void
default —
A device was removed after its confirm.
onFallback
(kind: "other-device" | "password") => void
default —
A fallback was chosen.
supported
boolean
default true
Whether this browser can create passkeys; false shows the unsupported message from the start.
now
number
default defaultPasskeyNow
The moment "used today" counts from, in ms.
ringCount
number
default 3
How many rings draw round the key, 2 to 5.
drawDuration
number
default 1400
Milliseconds each ring takes to draw while the prompt is open.
title
string
default "Add a passkey"
The heading.
status
"ready" | "loading" | "error"
default "ready"
Whether the device list has arrived.
onRetry
() => void
default —
Try again was pressed after the list failed to load.
ringStyle
"rings" | "arcs" | "dots"
default "rings"
The rings: full circles, broken arcs that turn both ways, or rings of dots.
density
"compact" | "cozy" | "roomy"
default "cozy"
Padding, row height and type size.
accent
"cobalt" | "mint" | "amber" | "ink" | string
default "cobalt"
The rings, the solid mark and Create: a named pigment or any CSS colour.
formatDate
(ms) => string
default "3 Sep" (UTC)
How a date is written.
maxHeight
number
default 560
The surface's height cap in px; the list scrolls inside it.
disabled
boolean
default false
Nothing can be enrolled, renamed or removed.
className
string
default —
Classes for the surface.