shadcn.io is not affiliated with official shadcn/ui
One-Time Link Login Block for React
A split sign-in about the life of a one-time link: the email drawn beside the form, then a Fresh, Used and Expired status strip with a 10-minute timer and demo controls to open the link twice, request a new one or skip to expiry.
Installation
Overview
Show people what a single-use link does, with this one-time link login block for React with Base UI. It's the sign-in page of Hushbox, a secure document-sharing tool, split in two between the page's rails. At the end, a drawn email shows what Hushbox would send: a "Sign in to Hushbox" button that works once and a six-digit code for when the button won't open. At the start, a Field asks for an address and the Shine Button sends the link, the only colored control. The form then turns, in the same space, into the link's status: a strip of three cells (Fresh, Used, Expired) with the current one filled, a Timer counting down from 10 minutes, and three demo controls. "Open the link (demo)" signs in and says the link is now used, pressed again it says the link was already used, "Skip to expiry (demo)" ends the 10 minutes at once, and "Request a new link" retires the old one for a fresh one. The drawn email follows the state, and below the large breakpoint it's hidden while the status and controls stay. It's built from Field, Input, Timer, Button, Shine Button and Guides, with a CSS entrance only. For document, finance and admin tools that avoid passwords.
FAQ
What stays in the page, and how do I wire real links?
All of it. Sending waits 700 ms and shows the status; opening, expiring and requesting only change local state, and a polite message says nothing was sent. In a product, create a random token on your server when the address is submitted, store its hash with an expiry 10 minutes ahead and a used flag, and email a link that carries it. When the link is opened, check the hash, the expiry and the flag, set the flag in the same step that starts the session, and refuse every later attempt. Replace the three demo controls with the real link in the email.
What are the three states, and what moves between them?
A link is Fresh until it is used or its 10 minutes pass. Opening a fresh link makes it Used; skipping to expiry, or the timer reaching zero, makes it Expired; a used or expired link never goes back. Requesting a new link starts a fresh one and retires the old, so a link you were sent earlier stops working the moment you ask for another. The strip, the timer line and a notice below it all follow the same state.
Is the timer real?
Yes. It starts when the link is sent, counts down from 10:00 in real time, and reaching zero expires the link. It lives in the status pane and starts over for each new link. The digits are hidden from screen readers, which get a sentence with the minutes and seconds instead. Under reduced motion the ticking digits give way to the sentence "Expires in 10 minutes".
Does the six-digit code in the email work?
It is part of the drawing, not a field: no input accepts it, so it opens nothing. It shows the usual pattern, a code printed in the email for people whose mail app strips buttons or opens links in the wrong browser, entered on the sign-in page itself. If you offer one, make it as single-use and short-lived as the link, and limit the attempts.
What happens on a phone?
The drawn email is hidden below the large breakpoint, since it only illustrates what the status already says. The form, the status strip, the timer and the controls take the full width, and the page keeps one height whichever state shows, so nothing moves when a link is used or expires.
Why is the Send button never disabled?
A disabled button can't explain itself and keyboard users can't reach it. Pressing Send with an empty or malformed address marks the field invalid, writes one sentence under it and moves focus there. Typing clears the problem, and the field keeps a line for its problem even when there is none.
Related
- Pro
Magic Link Login
PasswordlessA full-height passwordless sign-in for a newsletter tool: one email field, then a Check your inbox state with a drawn envelope, a Resend button that really waits 30 seconds, and a way to change the address.
- Pro
Email First Sign In Login
Step by stepAn identifier-first sign-in for an invoicing app: one email field, a lookup against two typed accounts, then either the password step with the address kept as a badge or account creation with the address carried over.
- Pro
OTP Verification Login
Codes and approvalsA code step for a parcel locker app: a six-digit field that checks itself on the sixth digit or on a paste, counts wrong codes down from three, and a resend button that waits 30 seconds after it is pressed.
- Pro
Session Expired Login
Sessions and devicesA re-authentication page for a document editor that keeps the email read-only, asks only for the password, shows where you were, and confirms before switching account.
- Pro
Passwordless Login
PasswordlessA full-height method picker for a podcast app: four hairline radio rows (email link, passkey, text code, authenticator app), a cell that says what happens next for the chosen way, and one button whose label follows the choice.
- Pro
Passkey Login
PasswordlessAn 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.