New

MagicLinkAuth

Email-only magic link auth with "Check your inbox" state, envelope icon, and resend countdown timer.

Auth & Onboardingmagic-linkemailpasswordlessauth

Dependencies

shadcn/ui components needed:

npx shadcn@latest add lucide-react

How to use this component

Copy the code below into your project. Make sure you have the required shadcn/ui dependencies installed. Then import and use the component in your pages or layouts.

Code

1"use client";
2
3import { useState, useEffect } from "react";
4import { Mail, ArrowLeft, Loader2, CheckCircle2 } from "lucide-react";
5
6export default function MagicLinkAuth() {
7 const [email, setEmail] = useState("");
8 const [sent, setSent] = useState(false);
9 const [countdown, setCountdown] = useState(0);
10 const [sending, setSending] = useState(false);
11
12 useEffect(() => {
13 if (countdown <= 0) return;
14 const t = setTimeout(() => setCountdown(countdown - 1), 1000);
15 return () => clearTimeout(t);
16 }, [countdown]);
17
18 const handleSend = () => {
19 setSending(true);
20 setTimeout(() => {
21 setSending(false);
22 setSent(true);
23 setCountdown(60);
24 }, 1500);
25 };
26
27 const handleResend = () => {
28 setCountdown(60);
29 };
30
31 if (sent) {
32 return (
33 <div className="mx-auto w-full max-w-md rounded-2xl border border-zinc-200 bg-white p-8 text-center shadow-xl dark:border-zinc-800 dark:bg-zinc-950">
34 <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-emerald-50 dark:bg-emerald-900/20">
35 <Mail className="h-8 w-8 text-emerald-600 dark:text-emerald-400" />
36 </div>
37 <h2 className="mb-2 text-xl font-bold text-zinc-900 dark:text-zinc-50">Check your inbox</h2>
38 <p className="mb-1 text-sm text-zinc-500 dark:text-zinc-400">We sent a magic link to</p>
39 <p className="mb-6 text-sm font-semibold text-zinc-900 dark:text-zinc-100">{email}</p>
40 <div className="mb-4 rounded-lg bg-zinc-50 p-4 dark:bg-zinc-900">
41 <div className="flex items-center justify-center gap-2 text-sm text-zinc-600 dark:text-zinc-400">
42 <CheckCircle2 className="h-4 w-4 text-emerald-500" />
43 Click the link in the email to sign in
44 </div>
45 </div>
46 <div className="space-y-3">
47 <button
48 onClick={handleResend}
49 disabled={countdown > 0}
50 className="w-full rounded-lg border border-zinc-200 px-4 py-2.5 text-sm font-medium text-zinc-700 transition-colors hover:bg-zinc-50 disabled:opacity-50 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800"
51 >
52 {countdown > 0 ? `Resend in ${countdown}s` : "Resend magic link"}
53 </button>
54 <button onClick={() => setSent(false)} className="flex w-full items-center justify-center gap-1.5 text-sm text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200">
55 <ArrowLeft className="h-3.5 w-3.5" /> Use a different email
56 </button>
57 </div>
58 </div>
59 );
60 }
61
62 return (
63 <div className="mx-auto w-full max-w-md rounded-2xl border border-zinc-200 bg-white p-8 shadow-xl dark:border-zinc-800 dark:bg-zinc-950">
64 <div className="mb-6 text-center">
65 <div className="mx-auto mb-3 flex h-12 w-12 items-center justify-center rounded-xl bg-gradient-to-br from-violet-500 to-indigo-600">
66 <Mail className="h-6 w-6 text-white" />
67 </div>
68 <h2 className="text-2xl font-bold tracking-tight text-zinc-900 dark:text-zinc-50">Sign in with email</h2>
69 <p className="mt-1 text-sm text-zinc-500 dark:text-zinc-400">No password needed — we&apos;ll send you a magic link</p>
70 </div>
71 <form onSubmit={(e) => { e.preventDefault(); handleSend(); }} className="space-y-4">
72 <div>
73 <label htmlFor="magic-email" className="mb-1.5 block text-sm font-medium text-zinc-700 dark:text-zinc-300">Email address</label>
74 <input id="magic-email" type="email" required placeholder="you@example.com" value={email} onChange={(e) => setEmail(e.target.value)} className="w-full rounded-lg border border-zinc-300 bg-transparent px-3.5 py-2.5 text-sm outline-none transition-colors placeholder:text-zinc-400 focus:border-violet-500 focus:ring-2 focus:ring-violet-500/20 dark:border-zinc-700 dark:text-zinc-100" />
75 </div>
76 <button type="submit" disabled={sending} className="flex w-full items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-violet-600 to-indigo-600 px-4 py-2.5 text-sm font-semibold text-white shadow-md transition-all hover:from-violet-500 hover:to-indigo-500 active:scale-[0.98] disabled:opacity-70">
77 {sending ? <><Loader2 className="h-4 w-4 animate-spin" /> Sending...</> : "Send magic link"}
78 </button>
79 </form>
80 </div>
81 );
82}

Related Auth & Onboarding Components

Command Palette

Search for a command to run...