shadcn.io is not affiliated with official shadcn/ui
Two-Step Setup Dialog Block for React
A cloud editor's security page with a three-step dialog shown open: a QR code and its key, eight backup codes to copy or download, and a six-digit check, ending in a note that two-step sign-in is on.
Installation
Overview
Walk people through adding a second step to signing in, with this enrolment dialog for React with Base UI. It opens from the security page of Wardfield, a cloud code editor: the page, a list of rows with a switch each, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner, and its header holds an outline Turn on two-step Button. The dialog is a stepper: a Steps header names Scan, Save codes and Verify. Step one shows a QR Code of a setup link beside the key to type if you can't scan, with a Copy Button. Step two lists eight backup codes with Copy all, a Download Trigger that saves them as a text file, and a required Checkbox that opens Next. Step three takes the six-digit code in an Input OTP. Next is the only Shine Button, and the last view is an Alert saying two-step sign-in is on in this demo, with the page's Two-step row turned On. For preview the dialog is drawn open in place when the page loads; the header's button opens the real Dialog. For security settings, accounts and any app with a second step.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused. The Turn on two-step button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same SetupFields component and share the block's state. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
How do the steps work?
The three views, and the closing note, share one grid cell with the unseen ones made invisible and inert, so the dialog keeps its height whichever you are on, and Back keeps what you typed or ticked. Next on the second step stays off until you tick that you saved the codes. The Steps header only shows where you are: it isn't a row of buttons, so the order can't be skipped.
Is the QR code real, and can I ship these codes?
The QR code is real and a phone's authenticator can scan it: it encodes an otpauth:// link with an account, an issuer and a key. But the key and the eight backup codes are typed in the file so the block is the same on every render, which means everyone sees the same ones. Never ship them: generate a key and codes for each account on your server and put them in place of SETUP_URI, SECRET and BACKUP_CODES.
What does the last step check?
Only that you typed 482913, the code in the hint, and it counts three tries: a wrong code says how many are left, and after the third the field locks until you go back or close the dialog. In your app verify the code on the server as a time-based one-time password (RFC 6238) against the key you stored for that person, allow a step of clock drift either way, switch two-step sign-in on only after a first code passes, and store the backup codes hashed.
What stays local?
Nothing is enrolled. Copy uses the real clipboard and Download saves a real text file of the typed codes, but a finished setup only turns the drawn Two-step row to On and says so in the polite status; the header's button becomes Start over, which turns it Off again to try another code.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus starts on the first control of the first step and stays inside until it closes, and Escape, Cancel and the close button return focus to the header's button. Each step is announced by the polite status line, and the QR code carries a text alternative: the key beside it. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. On a phone the copy shown on load docks to the foot of the page as a bottom sheet, the codes become one column and the body scrolls above the pinned actions; the real dialog keeps the Dialog's own phone layout.
Related
- Pro
Deactivate 2FA Dialog
Destructive confirmsA security page with its turn-off confirmation shown open: an alert dialog that lists what goes with two-step verification, asks for the password and a ticked acknowledgement, and keeps its destructive action quiet until both are done.
- Pro
PIN Keypad Dialog
Account and securityA mobile wallet's transfer review with its PIN dialog shown open: four masked slots over a keypad of twelve keys, typed digits and keypad presses writing the same value, and a fourth digit that approves.
- Pro
One-Time Code Input Form
Numbers and pickersA six-slot confirmation code in two groups of three with its behaviours in view: paste fills all six and checks at once, a wrong code is marked, counted and cleared, and a resend button waits 30 seconds.
- Pro
An account-security prompt to turn on two-factor sign-in: three radio cards for the method, a QR code with a made-up key and a six-digit code field for the app, a masked number for text messages, and a Turn on button that accepts the printed demo code.
- Pro
Passkeys Account
Sign-in methodsAn account's passkeys: a ruled list of what each one is, when it was created and last used, a name you edit in place, a guarded Remove, and a dialog from the header that names a new passkey.
- Pro
Session Timeout Dialog
Status and errorsA bank's accounts page with an alert dialog shown open that warns before an idle session ends: a one-minute clock with a draining bar, Stay signed in and Sign out now, and a signed-out view at zero.