shadcn.io is not affiliated with official shadcn/ui
Expired Link Error Block for React
A full-screen page for an expired password-reset link: the link's life drawn on a time axis, the facts in words, and an Email me a new link button that hands its place to a 30-second cooldown.
Installation
Overview
Tell people exactly why a reset link failed, with this expired link page for React with Base UI. It's the screen Hushpost, a private-newsletter tool, shows when someone opens a password-reset link too late: the page's two side rails run its full height and one band crosses the screen between two rules with a plus mark where each meets a rail. Over the heading, a drawn time axis shows the link's life: sent at 14:00, good for 15 minutes (a solid bar), then a dashed run to a marker at 16:40 with the words "2 h 25 min late". Under the heading, a list says what the page knows: the kind of link, the masked address it went to, when it was sent and when it ended. The one coloured control is the Shine Button Email me a new link: pressing it waits a moment, says honestly that nothing was sent, and then trades places with a Countdown Button that drains over 30 seconds before the Shine Button comes back. The rules come from Guides, and the entrance is CSS only. For password resets, magic links and verification emails.
FAQ
What does Email me a new link do, and what stays in the page?
Nothing leaves the page. Pressing it shows a spinner on the button for under a second, then a polite status line says that a new link would be on its way to the masked address and that nothing was sent in this demo, and focus moves to that line because the busy button drops it. To wire it for real, send the reset email from request (keep the same answer whether or not the address has an account) and keep the cooldown in step with your server's rate limit.
Where do the times on the axis come from?
They are constants at the top of the file: when the link was sent (SENT_AT), how long it lives (VALID_FOR) and the clock time the page was opened (NOW_AT), all in minutes after midnight UTC. The bar, the marker, the labels and the sentence are derived from them, so the drawing and the text can't disagree, and nothing reads the real clock. In your app, take the sent time and the lifetime from the token's record and the time from the server, so the server and the browser agree.
Should this page return an error status?
Yes, from your server: a component can't set it. An expired or used token is usually a 410 Gone (some teams use 400 or 404); send it so crawlers and monitors see an error and not a normal page. Keep the wording generic if the link could belong to someone else: this page says what happened to the link, never who it was for beyond the masked address the visitor already received.
Why does the button trade places with a countdown?
A second press right after the first would send two emails and make the first link useless, so the page asks for a short wait. The Countdown Button shows the seconds in its label and drains a fill behind it; it never changes size, and a screen reader hears one announcement when it starts ("Ask again in 30 s"), not one every second. When the 30 seconds are over the Shine Button returns and a polite line says so.
How is the time axis read without seeing it?
The drawing is decoration (hidden from assistive technology) and carries a caption for screen readers that says the same thing in a sentence; the list under the heading repeats every fact as text. Nothing is shown by colour alone: the solid bar is the time the link worked, the dashed run is the time since, and the marker's cross is the page's only status colour. The axis keeps its direction in right-to-left languages.
Related
- Pro
Expired Invitation Error
Locked and removedA full-screen page for an expired team invitation: the invitation drawn as a pass in a card in a card with an Expired stamp, its code with a Copy button, and an Ask for a new invite button that honestly sends nothing.
- Pro
Email Not Verified Error
Sign-in and identityA full-screen page for an unconfirmed email: a drawn mail list with Inbox, Spam and Promotions tabs showing where the message hides, an I've confirmed it button, a Resend the email button with a 30-second wait and a Change email field.
- Pro
Phone Not Verified Error
Sign-in and identityA full-screen page for an unconfirmed phone number: a Send the code button that waits 30 seconds, a six-slot code field with the demo code printed once, and a list of what is locked that flips to unlocked when the number is verified.
- Pro
Invalid Token Error
Sign-in and identityA full-screen invalid-token page for an identity API: three ruled checks (Format failed with the parts drawn, Signature and Expiry not checked), a masked fingerprint to copy, Sign in again, and a Report to security list of exactly what a report would attach.
- Pro
Session Expired Error
Sign-in and identityA full-screen session-ended page for a billing back office: a session ruler from 09:00 to 10:30 UTC with the active time solid and the idle gap hatched, a legend of when you signed in, were last active and were signed out, and a demo control that swaps the cause.
- Pro
Redirect Countdown Error
Not foundA full-screen page for an address that moved: eight ticks that empty one per second over the old address struck through the new one, a Stay here that cancels the redirect and a Go now, with nothing ever navigating.