- Gallery
- Auth & Onboarding
- MagicLinkAuth
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-reactHow 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";23import { useState, useEffect } from "react";4import { Mail, ArrowLeft, Loader2, CheckCircle2 } from "lucide-react";56export 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);1112 useEffect(() => {13 if (countdown <= 0) return;14 const t = setTimeout(() => setCountdown(countdown - 1), 1000);15 return () => clearTimeout(t);16 }, [countdown]);1718 const handleSend = () => {19 setSending(true);20 setTimeout(() => {21 setSending(false);22 setSent(true);23 setCountdown(60);24 }, 1500);25 };2627 const handleResend = () => {28 setCountdown(60);29 };3031 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 in44 </div>45 </div>46 <div className="space-y-3">47 <button48 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 email56 </button>57 </div>58 </div>59 );60 }6162 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'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}