Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Expired Link Error Block for Svelte

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.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Tell people exactly why a reset link failed, with this expired link page for Svelte with Ark 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.